diff --git a/.hgtags b/.hgtags
index 08ec2de7fcfd360afd0d22ea13c963255032bf99..c614db0d3e6ab5e840e5da4ec22102591b78b4be 100755
--- a/.hgtags
+++ b/.hgtags
@@ -72,35 +72,35 @@ b53a0576eec80614d7767ed72b40ed67aeff27c9 DRTVWR-38_2.5.2-release
 461c8c65b5c799ddfe365422f9be9c0095d91e7d 2.6.0-beta1-tip
 9e4641f4a7870c0f565a25a2971368d5a29516a1 2.6.0-beta2
 9e4641f4a7870c0f565a25a2971368d5a29516a1 DRTVWR-41_2.6.0-beta2
+42f32494bac475d0737799346f6831558ae8bf5d 2.6.0-release
+42f32494bac475d0737799346f6831558ae8bf5d DRTVWR-39_2.6.0-release
 c5bdef3aaa2744626aef3c217ce29e1900d357b3 2.6.1-beta1
 c5bdef3aaa2744626aef3c217ce29e1900d357b3 2.6.1-start
 c5bdef3aaa2744626aef3c217ce29e1900d357b3 DRTVWR-43_2.6.1-beta1
+c9182ed77d427c759cfacf49a7b71a2e20d522aa 2.6.1-release
+c9182ed77d427c759cfacf49a7b71a2e20d522aa DRTVWR-42_2.6.1-release
 56b2778c743c2a964d82e1caf11084d76a87de2c 2.6.2-start
 d1203046bb653b763f835b04d184646949d8dd5c 2.6.2-beta1
 d1203046bb653b763f835b04d184646949d8dd5c DRTVWR-45_2.6.2-beta1
-42f32494bac475d0737799346f6831558ae8bf5d 2.6.0-release
-42f32494bac475d0737799346f6831558ae8bf5d DRTVWR-39_2.6.0-release
-c9182ed77d427c759cfacf49a7b71a2e20d522aa 2.6.1-release
-c9182ed77d427c759cfacf49a7b71a2e20d522aa DRTVWR-42_2.6.1-release
+214180ad5714ce8392b82bbebcc92f4babd98300 2.6.2-release
+214180ad5714ce8392b82bbebcc92f4babd98300 DRTVWR-44_2.6.2-release
 52b2263ab28f0976c689fd0b76c55a9eb027cdbf end-of-develop.py
 ec32f1045e7c2644015245df3a9933620aa194b8 2.6.3-start
 d7fcefabdf32bb61a9ea6d6037c1bb26190a85bc 2.6.3-beta1
 d7fcefabdf32bb61a9ea6d6037c1bb26190a85bc DRTVWR-47_2.6.3-beta1
 0630e977504af5ea320c58d33cae4e1ddee793e9 2.6.3-beta2
 0630e977504af5ea320c58d33cae4e1ddee793e9 DRTVWR-48_2.6.3-beta2
+8f2da1701c81a62352df2b8d413d27fb2cade9a6 2.6.3-release
+8f2da1701c81a62352df2b8d413d27fb2cade9a6 DRTVWR-46_2.6.3-release
 3178e311da3a8739a85363665006ea3c4610cad4 dons-headless-hackathon-work
-214180ad5714ce8392b82bbebcc92f4babd98300 2.6.2-release
-214180ad5714ce8392b82bbebcc92f4babd98300 DRTVWR-44_2.6.2-release
 7db558aaa7c176f2022b3e9cfe38ac72f6d1fccd 2.6.5-beta1
 7db558aaa7c176f2022b3e9cfe38ac72f6d1fccd DRTVWR-50_2.6.5-beta1
-8f2da1701c81a62352df2b8d413d27fb2cade9a6 2.6.3-release
-8f2da1701c81a62352df2b8d413d27fb2cade9a6 DRTVWR-46_2.6.3-release
 800cefce8d364ffdd2f383cbecb91294da3ea424 2.6.6-start
 bb1075286b3b147b1dae2e3d6b2d56f04ff03f35 2.6.6-beta1
 bb1075286b3b147b1dae2e3d6b2d56f04ff03f35 DRTVWR-52_2.6.6-beta1
-5e349dbe9cc84ea5795af8aeb6d473a0af9d4953 2.6.8-start
 dac76a711da5f1489a01c1fa62ec97d99c25736d 2.6.6-release
 dac76a711da5f1489a01c1fa62ec97d99c25736d DRTVWR-51_2.6.6-release
+5e349dbe9cc84ea5795af8aeb6d473a0af9d4953 2.6.8-start
 beafa8a9bd1d1b670b7523d865204dc4a4b38eef 2.6.8-beta1
 beafa8a9bd1d1b670b7523d865204dc4a4b38eef DRTVWR-55_2.6.8-beta1
 be2000b946f8cb3de5f44b2d419287d4c48ec4eb 2.6.8-release
@@ -119,50 +119,50 @@ e67da2c6e3125966dd49eef98b36317afac1fcfe 2.6.9-start
 9f79a6ed8fdcd2f3dac33ea6b3236eeb278dccfe 2.7.2-start
 e0dc8b741eaa27dcdfbc9e956bb2579b954d15eb 2.7.2-beta1
 e0dc8b741eaa27dcdfbc9e956bb2579b954d15eb DRTVWR-63_2.7.2-beta1
-6a3e7e403bd19e45fdfc2fcc716867af3ab80861 2.7.3-start
 fe3a8e7973072ea62043c08b19b66626c1a720eb 2.7.1-release
 fe3a8e7973072ea62043c08b19b66626c1a720eb 2.7.2-release
 fe3a8e7973072ea62043c08b19b66626c1a720eb DRTVWR-60_2.7.1-release
 fe3a8e7973072ea62043c08b19b66626c1a720eb DRTVWR-62_2.7.2-release
+6a3e7e403bd19e45fdfc2fcc716867af3ab80861 2.7.3-start
 6af10678de4736222b2c3f7e010e984fb5b327de 2.7.4-start
 be963a4eef635542f9617d7f5fd22ba48fb71958 2.7.4-beta1
 be963a4eef635542f9617d7f5fd22ba48fb71958 DRTVWR-67_2.7.4-beta1
+057f319dd8eccdf63a54d99686c68cdcb31b6abc 2.7.4-release
+057f319dd8eccdf63a54d99686c68cdcb31b6abc DRTVWR-66_2.7.4-release
 19a498fa62570f352d7d246f17e3c81cc1d82d8b 2.7.5-start
 09984bfa6cae17e0f72d02b75c1b7393c65eecfc 2.7.5-beta1
 09984bfa6cae17e0f72d02b75c1b7393c65eecfc DRTVWR-69_2.7.5-beta1
+6866d9df6efbd441c66451debd376d21211de39c 2.7.5-release
+6866d9df6efbd441c66451debd376d21211de39c DRTVWR-68_2.7.5-release
 e1ed60913230dd64269a7f7fc52cbc6004f6d52c 2.8.0-beta1
 e1ed60913230dd64269a7f7fc52cbc6004f6d52c 2.8.0-start
 e1ed60913230dd64269a7f7fc52cbc6004f6d52c DRTVWR-71_2.8.0-beta1
-057f319dd8eccdf63a54d99686c68cdcb31b6abc 2.7.4-release
-057f319dd8eccdf63a54d99686c68cdcb31b6abc DRTVWR-66_2.7.4-release
-6866d9df6efbd441c66451debd376d21211de39c 2.7.5-release
-6866d9df6efbd441c66451debd376d21211de39c DRTVWR-68_2.7.5-release
+493d9127ee50e84ba08a736a65a23ca86f7a5b01 2.8.0-release
+493d9127ee50e84ba08a736a65a23ca86f7a5b01 DRTVWR-70_2.8.0-release
 502f6a5deca9365ddae57db4f1e30172668e171e 2.8.1-start
 2c7e459e0c883f8e406b932e41e60097e9ee077e 2.8.1-beta1
 2c7e459e0c883f8e406b932e41e60097e9ee077e DRTVWR-73_2.8.1-beta1
-493d9127ee50e84ba08a736a65a23ca86f7a5b01 2.8.0-release
-493d9127ee50e84ba08a736a65a23ca86f7a5b01 DRTVWR-70_2.8.0-release
-54bc7823ad4e3a436fef79710f685a7372bbf795 2.8.2-start
-ac0f1a132d35c02a58861d37cca75b0429ac9137 2.8.3-start
 29e93d7e19991011bd12b5748142b11a5dcb4370 2.8.1-release
 29e93d7e19991011bd12b5748142b11a5dcb4370 DRTVWR-72_2.8.1-release
 4780e3bd2b3042f91be3426151f28c30d199bb3b 2.8.1-hotfix
 4780e3bd2b3042f91be3426151f28c30d199bb3b DRTVWR-76_2.8.1-hotfix
+54bc7823ad4e3a436fef79710f685a7372bbf795 2.8.2-start
+ac0f1a132d35c02a58861d37cca75b0429ac9137 2.8.3-start
 599677276b227357140dda35bea4a2c18e2e67b5 2.8.3-beta1
 599677276b227357140dda35bea4a2c18e2e67b5 DRTVWR-75_2.8.3-beta1
+fb85792b84bf28428889c4cc966469d92e5dac4c 2.8.3-release
+fb85792b84bf28428889c4cc966469d92e5dac4c DRTVWR-74_2.8.3-release
 6b678ea52f90d5c14181661dcd2546e25bde483e 3.0.0-start
 b0be6ce3adfef3a014a2389d360539f8a86c5439 3.0.0-beta1
 b0be6ce3adfef3a014a2389d360539f8a86c5439 DRTVWR-78_3.0.0-beta1
-fb85792b84bf28428889c4cc966469d92e5dac4c 2.8.3-release
-fb85792b84bf28428889c4cc966469d92e5dac4c DRTVWR-74_2.8.3-release
+1778f26b6d0ae762dec3ca37140f66620f2485d9 3.0.0-release
+1778f26b6d0ae762dec3ca37140f66620f2485d9 DRTVWR-77_3.0.0-release
 82a2079ffcb57ecb1b3849cb41376b443e1eb912 3.0.1-start
 364fd63517fbacbbcb9129d096187171ba8c9e48 3.0.1-beta1
 364fd63517fbacbbcb9129d096187171ba8c9e48 DRTVWR-81_3.0.1-beta1
 f2412ecd6740803ea9452f1d17fd872e263a0df7 3.0.2-start
 42784bf50fa01974bada2a1af3892ee09c93fcda 3.0.2-beta1
 42784bf50fa01974bada2a1af3892ee09c93fcda DRTVWR-83_3.0.2-beta1
-1778f26b6d0ae762dec3ca37140f66620f2485d9 3.0.0-release
-1778f26b6d0ae762dec3ca37140f66620f2485d9 DRTVWR-77_3.0.0-release
 e5c9af2d7980a99a71650be3a0cf7b2b3c3b897e 3.0.2-beta2
 e5c9af2d7980a99a71650be3a0cf7b2b3c3b897e DRTVWR-86_3.0.2-beta2
 b95ddac176ac944efdc85cbee94ac2e1eab44c79 3.0.3-start
@@ -170,9 +170,9 @@ b95ddac176ac944efdc85cbee94ac2e1eab44c79 3.0.3-start
 6694f3f062aa45f64ab391d25a3eb3d5eb1b0871 DRTVWR-85_3.0.3-beta1
 61aa7974df089e8621fe9a4c69bcdefdb3cc208a 3.0.3-beta2
 61aa7974df089e8621fe9a4c69bcdefdb3cc208a DRTVWR-89_3.0.3-beta2
-586907287be581817b2422b5137971b22d54ea48 3.0.4-start
 0496d2f74043cf4e6058e76ac3db03d44cff42ce 3.0.3-release
 0496d2f74043cf4e6058e76ac3db03d44cff42ce DRTVWR-84_3.0.3-release
+586907287be581817b2422b5137971b22d54ea48 3.0.4-start
 92a3aa04775438226399b19deee12ac3b5a62838 3.0.5-start
 c7282e59f374ee904bd793c3c444455e3399b0c5 3.1.0-start
 2657fa785bbfac115852c41bd0adaff74c2ad5da 3.1.0-beta1
@@ -193,11 +193,11 @@ e440cd1dfbd128d7d5467019e497f7f803640ad6 DRTVWR-95_3.2.0-beta1
 c4911ec8cd81e676dfd2af438b3e065407a94a7a 3.2.1-start
 9e390d76807fa70d356b8716fb83b8ce42a629ef 3.2.1-beta1
 9e390d76807fa70d356b8716fb83b8ce42a629ef DRTVWR-100_3.2.1-beta1
+a8c7030d6845186fac7c188be4323a0e887b4184 3.2.1-release
+a8c7030d6845186fac7c188be4323a0e887b4184 DRTVWR-99_3.2.1-release
 40b46edba007d15d0059c80864b708b99c1da368 3.2.2-start
 523df3e67378541498d516d52af4402176a26bac 3.2.2-beta1
 523df3e67378541498d516d52af4402176a26bac DRTVWR-102_3.2.2-beta1
-a8c7030d6845186fac7c188be4323a0e887b4184 3.2.1-release
-a8c7030d6845186fac7c188be4323a0e887b4184 DRTVWR-99_3.2.1-release
 80f3e30d8aa4d8f674a48bd742aaa6d8e9eae0b5 3.2.3-start
 3fe994349fae64fc40874bb59db387131eb35a41 3.2.4-beta1
 3fe994349fae64fc40874bb59db387131eb35a41 3.2.4-start
@@ -279,6 +279,10 @@ a8057e1b9a1246b434a27405be35e030f7d28b0c 3.3.4-beta3
 9cd174d3a54d93d409a7c346a15b8bfb40fc58f4 DRTVWR-184
 ab2ffc547c8a8950ff187c4f6c95e5334fab597b 3.3.4-beta5
 28e100d0379a2b0710c57647a28fc5239d3d7b99 3.3.4-release
+6dfb0fba782c9233dd95f24ec48146db0d3f210b DRTVWR-199
+7c9102fb998885621919f2474a002c35b583539b 3.3.4-release2
+8c9085066c78ed5f6c9379dc054c82a6fcdb1851 DRTVWR-207
+351eea5f9dc192fc5ddea3b02958de97677a0a12 3.3.4-release3
 005dfe5c4c377207d065fb27858d2eb0b53b143a DRTVWR-167
 888768f162d2c0a8de1dcc5fb9a08bd8bd120a6b DRTVWR-175
 a8b3eca451a9eaab59987efb0ab1c4217e3f2dcc DRTVWR-182
@@ -294,13 +298,9 @@ ae5c83dd61d2d37c45f1d5b8bf2b036d87599f1b DRTVWR-198
 b1dbb1a83f48f93f6f878cff9e52d2cb635e145c 3.4.0-beta2
 37402e2b19af970d51b0a814d79892cc5647532b DRTVWR-200
 182a9bf30e81070361bb020a78003b1cf398e79c 3.4.0-beta3
-6dfb0fba782c9233dd95f24ec48146db0d3f210b DRTVWR-199
-7c9102fb998885621919f2474a002c35b583539b 3.3.4-release2
 7649a3dff5ec22d3727377e5f02efd0f421e4cb5 DRTVWR-201
 84fb70dfe3444e75a44fb4bee43e2fc8221cebdd 3.4.0-beta4
 573e863be2f26d3687161def4b9fea9b7038dda8 3.4.0-beta5
-8c9085066c78ed5f6c9379dc054c82a6fcdb1851 DRTVWR-207
-351eea5f9dc192fc5ddea3b02958de97677a0a12 3.3.4-release3
 af7b28e75bd5a629cd9e0dc46fb3f1757626f493 DRTVWR-212
 015012c2b740ccdec8a8c3d6e5f898449ecfe0b8 DRTVWR-213
 62b07aa81b1957897c3846292bb9412977b0af6c 3.3.4-beta6
@@ -457,3 +457,8 @@ a314f1c94374ab1f6633dd2983f7090a68663eb2 3.5.2-beta4
 9013c07bfe1c51107233f1924dccdcc5057dd909 3.5.2-beta6
 9b1b6f33aa5394b27bb652b31b5cb81ef6060370 3.5.2-release
 a277b841729f2a62ba1e34acacc964bc13c1ad6f 3.5.3-release
+fb1630153bac5552046ea914af3f14deabc1def8 3.6.0-materials-beta1
+69429d81ae4dd321eda2607901ef0a0fde71b54c 3.6.0-release
+69429d81ae4dd321eda2607901ef0a0fde71b54c 3.6.0-release
+0a56f33ad6aa112032b14a41dad759ad377bdde9 3.6.0-release
+75cf8e855ae1af6895a35da475314c2b5acf1850 3.6.1-release
diff --git a/BuildParams b/BuildParams
index a4b361261fe292796dbcebfed82794f22cf5110f..84d30f651bad54782baf50b8fb0f3dcb4e8c4900 100755
--- a/BuildParams
+++ b/BuildParams
@@ -60,6 +60,7 @@ viewer-release.build_debug_release_separately = true
 viewer-release.build_viewer_update_version_manager = true
 viewer-release.codeticket_add_context = false
 
+
 # ========================================
 # mesh-development
 # ========================================
@@ -122,6 +123,14 @@ viewer-pathfinding.build_CYGWIN_Debug = false
 viewer-pathfinding.build_viewer_update_version_manager = false
 
 # ========================================
+# viewer-materials
+# ========================================
+
+viewer-materials.viewer_channel = "Second Life Beta Materials"
+viewer-materials.build_debug_release_separately = true
+viewer-materials.build_CYGWIN_Debug = false
+viewer-materials.build_viewer_update_version_manager = false
+
 # viewer-chui
 #
 # ========================================
@@ -189,3 +198,5 @@ runway.build_viewer_update_version_manager = false
 
 
 # eof
+
+
diff --git a/NORSPEC-207.patch b/NORSPEC-207.patch
new file mode 100644
index 0000000000000000000000000000000000000000..a1c1447bdab6fdb46bd916532862eedb00bc36e0
--- /dev/null
+++ b/NORSPEC-207.patch
@@ -0,0 +1,164 @@
+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 148ca1710b50ba9c45e192b62ee35d6c3460a89f..628d3f688338f1b4ad044292fa89c81f216c4350 100755
--- a/autobuild.xml
+++ b/autobuild.xml
@@ -498,9 +498,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-	      <string>10352aab979c333a52dbad21b6e6fba9</string>
+              <string>10352aab979c333a52dbad21b6e6fba9</string>
               <key>url</key>
-	      <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmodex-private/rev/274403/arch/Darwin/installer/fmodex-4.44-darwin-20130419.tar.bz2</string>
+              <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmodex-private/rev/274403/arch/Darwin/installer/fmodex-4.44-darwin-20130419.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin</string>
@@ -510,7 +510,7 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-          <string>79e45527aa9fb90b813599dff5ce01a7</string>
+              <string>79e45527aa9fb90b813599dff5ce01a7</string>
               <key>url</key>
               <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmodex-private/rev/274378/arch/Linux/installer/fmodex-4.44-linux-20130419.tar.bz2</string>
             </map>
@@ -522,9 +522,9 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-	      <string>0980cdf98a322a780ba739e324d0b955</string>
+	      <string>91752db72202807cffb33c1ec3fd90fc</string>
               <key>url</key>
-	      <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmodex-private/rev/274401/arch/CYGWIN/installer/fmodex-4.44-windows-20130419.tar.bz2</string>
+	      <string>http://s3-proxy.lindenlab.com/private-builds-secondlife-com/hg/repo/3p-fmodex-private/rev/276321/arch/CYGWIN/installer/fmodex-4.44-windows-20130521.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -747,7 +747,6 @@
           </map>
         </map>
       </map>
-
       <key>google_breakpad</key>
       <map>
         <key>license</key>
@@ -763,9 +762,9 @@
             <key>archive</key>
             <map>
            <key>hash</key>
-	   <string>aff5566e04003de0383941981198e04e</string>
+	      <string>aff5566e04003de0383941981198e04e</string>
           <key>url</key>
-          <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273073/arch/Darwin/installer/google_breakpad-0.0.0-rev1099-darwin-20130329.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273073/arch/Darwin/installer/google_breakpad-0.0.0-rev1099-darwin-20130329.tar.bz2</string>
             </map>
             <key>name</key>
             <string>darwin</string>
@@ -777,7 +776,7 @@
              <key>hash</key>
 	         <string>52257e5eb166a0b69c9c0c38f6e1920e</string>
              <key>url</key>
-	         <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273079/arch/Linux/installer/google_breakpad-0.0.0-rev1099-linux-20130329.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273079/arch/Linux/installer/google_breakpad-0.0.0-rev1099-linux-20130329.tar.bz2</string>
             </map>
             <key>name</key>
             <string>linux</string>
@@ -789,7 +788,7 @@
               <key>hash</key>
 	      <string>d812a6dfcabe6528198a3191068dac09</string>
               <key>url</key>
-             <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273073/arch/CYGWIN/installer/google_breakpad-0.0.0-rev1099-windows-20130329.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-breakpad/rev/273073/arch/CYGWIN/installer/google_breakpad-0.0.0-rev1099-windows-20130329.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -835,9 +834,45 @@
             <key>archive</key>
             <map>
               <key>hash</key>
-              <string>98994d5b0b4b3d43be22aa6a5c36e6fa</string>
+              <string>d2542614df9dd99cbb5ff67e76d4a6c1</string>
               <key>url</key>
-		<string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-mock-graham/rev/272961/arch/CYGWIN/installer/gmock-1.6.0-windows-20130327.tar.bz2</string>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-mock/rev/274899/arch/CYGWIN/installer/gmock-1.6.0-windows-20130426.tar.bz2</string>
+            </map>
+            <key>name</key>
+            <string>windows</string>
+          </map>
+        </map>
+      </map>
+      <key>gperftools</key>
+      <map>
+        <key>license</key>
+        <string>bsd</string>
+        <key>license_file</key>
+        <string>LICENSES/gperftools.txt</string>
+        <key>name</key>
+        <string>gperftools</string>
+        <key>platforms</key>
+        <map>
+          <key>linux</key>
+          <map>
+            <key>archive</key>
+            <map>
+              <key>hash</key>
+              <string>8aedfdcf670348c18a9991ae1b384a61</string>
+              <key>url</key>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-perftools/rev/262672/arch/Linux/installer/gperftools-2.0-linux-20120727.tar.bz2</string>
+            </map>
+            <key>name</key>
+            <string>linux</string>
+          </map>
+          <key>windows</key>
+          <map>
+            <key>archive</key>
+            <map>
+              <key>hash</key>
+              <string>f62841804acb91e1309603a84f3f0ce8</string>
+              <key>url</key>
+              <string>http://automated-builds-secondlife-com.s3.amazonaws.com/hg/repo/3p-google-perftools/rev/262672/arch/CYGWIN/installer/gperftools-2.0-windows-20120727.tar.bz2</string>
             </map>
             <key>name</key>
             <string>windows</string>
@@ -2532,7 +2567,7 @@
                   <string>"Visual Studio 10"</string>
                   <string>-DUNATTENDED:BOOL=ON</string>
                   <string>-DUSE_KDU=FALSE</string>
-                </array>
+                  </array>
               </map>
               <key>name</key>
               <string>DebugOS</string>
@@ -2620,7 +2655,7 @@
                   <string>-DUNATTENDED:BOOL=ON</string>
                   <string>-DINSTALL_PROPRIETARY=FALSE</string>
                   <string>-DUSE_KDU=FALSE</string>
-                </array>
+                  </array>
               </map>
               <key>name</key>
               <string>RelWithDebInfoOS</string>
@@ -2707,7 +2742,7 @@
                   <string>-DUNATTENDED:BOOL=ON</string>
                   <string>-DINSTALL_PROPRIETARY=FALSE</string>
                   <string>-DUSE_KDU=FALSE</string>
-                </array>
+                  </array>
               </map>
               <key>name</key>
               <string>ReleaseOS</string>
diff --git a/doc/contributions.txt b/doc/contributions.txt
index 8c5bb3d5763a496c05784b980182836c8f8e448e..66ccb404a8cfee9255f7796bdddab580f35cd6ba 100755
--- a/doc/contributions.txt
+++ b/doc/contributions.txt
@@ -404,6 +404,7 @@ Ganymedes Costagravas
 Geenz Spad
 	STORM-1823
 	STORM-1900
+	NORSPEC-229
 Gene Frostbite
 GeneJ Composer
 Geneko Nemeth
@@ -647,6 +648,7 @@ Jonathan Yap
 	STORM-1872
 	STORM-1858
 	STORM-1862
+	OPEN-161
 Kadah Coba
 	STORM-1060
     STORM-1843
@@ -1023,6 +1025,7 @@ Ryozu Kojima
 	VWR-287
 Sachi Vixen
 Sahkolihaa Contepomi
+	MATBUG-102
 Saii Hallard
 SaintLEOlions Zimer
 Salahzar Stenvaag
@@ -1173,6 +1176,7 @@ Techwolf Lupindo
 	SNOW-746
 	VWR-12385
 	VWR-20893
+	OPEN-161
 Templar Merlin
 tenebrous pau
 	VWR-247
@@ -1240,6 +1244,7 @@ Vadim Bigbear
 	VWR-2681
 Vaalith Jinn
     STORM-64
+    MATBUG-8
 Vector Hastings
 	VWR-8726
 Veritas Raymaker
diff --git a/indra/cmake/APR.cmake b/indra/cmake/APR.cmake
index 492ba2adea1249606fe704ad404f42b791e5a80e..a87027f5f64ba898a5e145d0ccf1cd32699213b9 100755
--- a/indra/cmake/APR.cmake
+++ b/indra/cmake/APR.cmake
@@ -49,7 +49,7 @@ else (STANDALONE)
   set(APR_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include/apr-1)
 
   if (LINUX)
-    list(APPEND APRUTIL_LIBRARIES ${DB_LIBRARIES} uuid)
+      list(APPEND APRUTIL_LIBRARIES ${DB_LIBRARIES} uuid)
     list(APPEND APRUTIL_LIBRARIES ${DB_LIBRARIES} rt)
   endif (LINUX)
 endif (STANDALONE)
diff --git a/indra/cmake/BuildVersion.cmake b/indra/cmake/BuildVersion.cmake
index 0094e313c7916d72c6d844ad62f852f842debaf0..b9ec8f5266beb054d97c26544b03c294b6ffcfde 100755
--- a/indra/cmake/BuildVersion.cmake
+++ b/indra/cmake/BuildVersion.cmake
@@ -18,7 +18,7 @@ if (NOT DEFINED VIEWER_SHORT_VERSION) # will be true in indra/, false in indra/n
            find_program(MERCURIAL hg)
            if (DEFINED MERCURIAL)
               execute_process(
-                 COMMAND ${MERCURIAL} parents --template "{rev}"
+                 COMMAND ${MERCURIAL} log -r tip --template "{p1rev}"
                  OUTPUT_VARIABLE VIEWER_VERSION_REVISION
                  OUTPUT_STRIP_TRAILING_WHITESPACE
                  )
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 246b9680e8519d0ae2ddb22abccb914571d192c4..10a23ea068f91945d0071edf1a6b9bf349ea913e 100755
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -12,6 +12,7 @@ set(cmake_SOURCE_FILES
     Audio.cmake
     BerkeleyDB.cmake
     Boost.cmake
+    BuildVersion.cmake
     CARes.cmake
     CMakeCopyIfDifferent.cmake
     ConfigurePkgConfig.cmake
diff --git a/indra/cmake/DragDrop.cmake b/indra/cmake/DragDrop.cmake
index b70aa6b6ee8c28c3b3887ac961cbafd0227a4160..73ef59b18fc35724c94e0b8d4a5ade89e63aa246 100755
--- a/indra/cmake/DragDrop.cmake
+++ b/indra/cmake/DragDrop.cmake
@@ -1,20 +1,20 @@
 # -*- cmake -*-
 
-set(OS_DRAG_DROP ON CACHE BOOL "Build the viewer with OS level drag and drop turned on or off")
+  set(OS_DRAG_DROP ON CACHE BOOL "Build the viewer with OS level drag and drop turned on or off")
 
-if (OS_DRAG_DROP)
+  if (OS_DRAG_DROP)
 
-  if (WINDOWS)
-    add_definitions(-DLL_OS_DRAGDROP_ENABLED=1)
-  endif (WINDOWS)
+    if (WINDOWS)
+      add_definitions(-DLL_OS_DRAGDROP_ENABLED=1)
+    endif (WINDOWS)
 
-  if (DARWIN)
-    add_definitions(-DLL_OS_DRAGDROP_ENABLED=1)
-  endif (DARWIN)
+    if (DARWIN)
+      add_definitions(-DLL_OS_DRAGDROP_ENABLED=1)
+    endif (DARWIN)
 
-  if (LINUX)
-    add_definitions(-DLL_OS_DRAGDROP_ENABLED=0)
-  endif (LINUX)
+    if (LINUX)
+      add_definitions(-DLL_OS_DRAGDROP_ENABLED=0)
+    endif (LINUX)
 
-endif (OS_DRAG_DROP)
+  endif (OS_DRAG_DROP)
 
diff --git a/indra/cmake/Havok.cmake b/indra/cmake/Havok.cmake
index 44f81ce332a92a6b77b786d2e88773bb70ed7aca..8b7f01d20b5020e9811eacc288ee4827bd9581c0 100755
--- a/indra/cmake/Havok.cmake
+++ b/indra/cmake/Havok.cmake
@@ -12,14 +12,14 @@ set(HAVOK_DEBUG_LIBRARY_PATH ${LIBS_PREBUILT_DIR}/lib/debug/havok-fulldebug)
 set(HAVOK_RELEASE_LIBRARY_PATH ${LIBS_PREBUILT_DIR}/lib/release/havok)
 
 if (LL_DEBUG_HAVOK)
-  if (WIN32)
-    # Always link relwithdebinfo to havok-hybrid on windows.
-    set(HAVOK_RELWITHDEBINFO_LIBRARY_PATH ${LIBS_PREBUILT_DIR}/lib/debug/havok-hybrid)
-  else (WIN32)
-    set(HAVOK_RELWITHDEBINFO_LIBRARY_PATH ${LIBS_PREBUILT_DIR}/lib/debug/havok-fulldebug)
-  endif (WIN32)
+   if (WIN32)
+      # Always link relwithdebinfo to havok-hybrid on windows.
+      set(HAVOK_RELWITHDEBINFO_LIBRARY_PATH ${LIBS_PREBUILT_DIR}/lib/debug/havok-hybrid)
+   else (WIN32)
+      set(HAVOK_RELWITHDEBINFO_LIBRARY_PATH ${LIBS_PREBUILT_DIR}/lib/debug/havok-fulldebug)
+   endif (WIN32)
 else (LL_DEBUG_HAVOK)
-  set(HAVOK_RELWITHDEBINFO_LIBRARY_PATH ${LIBS_PREBUILT_DIR}/lib/release/havok)
+   set(HAVOK_RELWITHDEBINFO_LIBRARY_PATH ${LIBS_PREBUILT_DIR}/lib/release/havok)
 endif (LL_DEBUG_HAVOK)
 
 set(HAVOK_LIBS
@@ -51,14 +51,14 @@ unset(HK_RELWITHDEBINFO_LIBRARIES)
 
 # *TODO: Figure out why we need to extract like this...
 foreach(HAVOK_LIB ${HAVOK_LIBS})
-  find_library(HAVOK_DEBUG_LIB_${HAVOK_LIB}   ${HAVOK_LIB} PATHS ${HAVOK_DEBUG_LIBRARY_PATH})
-  find_library(HAVOK_RELEASE_LIB_${HAVOK_LIB} ${HAVOK_LIB} PATHS ${HAVOK_RELEASE_LIBRARY_PATH})
-  find_library(HAVOK_RELWITHDEBINFO_LIB_${HAVOK_LIB} ${HAVOK_LIB} PATHS ${HAVOK_RELWITHDEBINFO_LIBRARY_PATH})
-  
-  if(LINUX)
-    set(debug_dir "${HAVOK_DEBUG_LIBRARY_PATH}/${HAVOK_LIB}")
-    set(release_dir "${HAVOK_RELEASE_LIBRARY_PATH}/${HAVOK_LIB}")
-    set(relwithdebinfo_dir "${HAVOK_RELWITHDEBINFO_LIBRARY_PATH}/${HAVOK_LIB}")
+        find_library(HAVOK_DEBUG_LIB_${HAVOK_LIB}   ${HAVOK_LIB} PATHS ${HAVOK_DEBUG_LIBRARY_PATH})
+        find_library(HAVOK_RELEASE_LIB_${HAVOK_LIB} ${HAVOK_LIB} PATHS ${HAVOK_RELEASE_LIBRARY_PATH})
+        find_library(HAVOK_RELWITHDEBINFO_LIB_${HAVOK_LIB} ${HAVOK_LIB} PATHS ${HAVOK_RELWITHDEBINFO_LIBRARY_PATH})
+        
+        if(LINUX)
+            set(debug_dir "${HAVOK_DEBUG_LIBRARY_PATH}/${HAVOK_LIB}")
+            set(release_dir "${HAVOK_RELEASE_LIBRARY_PATH}/${HAVOK_LIB}")
+            set(relwithdebinfo_dir "${HAVOK_RELWITHDEBINFO_LIBRARY_PATH}/${HAVOK_LIB}")
 
     # Try to avoid extracting havok library each time we run cmake.
     if("${havok_${HAVOK_LIB}_extracted}" STREQUAL "" AND EXISTS "${CMAKE_BINARY_DIR}/temp/havok_${HAVOK_LIB}_extracted")
@@ -77,35 +77,35 @@ foreach(HAVOK_LIB ${HAVOK_LIBS})
       if(DEBUG_PREBUILT)
         MESSAGE(STATUS "${cmd} ${debug_dir}")
       endif(DEBUG_PREBUILT)
-      exec_program( ${cmd} ${HAVOK_DEBUG_LIBRARY_PATH} ARGS ${debug_dir} OUTPUT_VARIABLE rv)
+            exec_program( ${cmd} ${HAVOK_DEBUG_LIBRARY_PATH} ARGS ${debug_dir} OUTPUT_VARIABLE rv)
 
       if(DEBUG_PREBUILT)
         MESSAGE(STATUS "${cmd} ${release_dir}")
       endif(DEBUG_PREBUILT)
-      exec_program( ${cmd} ${HAVOK_RELEASE_LIBRARY_PATH} ARGS ${release_dir} OUTPUT_VARIABLE rv)
+            exec_program( ${cmd} ${HAVOK_RELEASE_LIBRARY_PATH} ARGS ${release_dir} OUTPUT_VARIABLE rv)
 
       if(DEBUG_PREBUILT)
         MESSAGE(STATUS "${cmd} ${relwithdebinfo_dir}")
       endif(DEBUG_PREBUILT)
-      exec_program( ${cmd} ${HAVOK_RELWITHDEBINFO_LIBRARY_PATH} ARGS ${relwithdebinfo_dir} OUTPUT_VARIABLE rv)
+            exec_program( ${cmd} ${HAVOK_RELWITHDEBINFO_LIBRARY_PATH} ARGS ${relwithdebinfo_dir} OUTPUT_VARIABLE rv)
 
-      set(cmd "ar")
-      set(arg " -xv")
-      set(arg "${arg} ../lib${HAVOK_LIB}.a")
+            set(cmd "ar")
+            set(arg " -xv")
+            set(arg "${arg} ../lib${HAVOK_LIB}.a")
       if(DEBUG_PREBUILT)
         MESSAGE(STATUS "cd ${debug_dir} && ${cmd} ${arg}")
       endif(DEBUG_PREBUILT)
-      exec_program( ${cmd} ${debug_dir} ARGS ${arg} OUTPUT_VARIABLE rv)
+            exec_program( ${cmd} ${debug_dir} ARGS ${arg} OUTPUT_VARIABLE rv)
 
       if(DEBUG_PREBUILT)
         MESSAGE(STATUS "cd ${release_dir} && ${cmd} ${arg}")
       endif(DEBUG_PREBUILT)
-      exec_program( ${cmd} ${release_dir} ARGS ${arg} OUTPUT_VARIABLE rv)
+            exec_program( ${cmd} ${release_dir} ARGS ${arg} OUTPUT_VARIABLE rv)
 
       if(DEBUG_PREBUILT)
         MESSAGE(STATUS "cd ${relwithdebinfo_dir} && ${cmd} ${arg}")
       endif(DEBUG_PREBUILT)
-      exec_program( ${cmd} ${relwithdebinfo_dir} ARGS ${arg} OUTPUT_VARIABLE rv)
+            exec_program( ${cmd} ${relwithdebinfo_dir} ARGS ${arg} OUTPUT_VARIABLE rv)
 
       # Just assume success for now.
       set(havok_${HAVOK_LIB}_extracted 0)
@@ -113,9 +113,9 @@ foreach(HAVOK_LIB ${HAVOK_LIBS})
 
     endif(${CMAKE_BINARY_DIR}/temp/havok-source_installed IS_NEWER_THAN ${CMAKE_BINARY_DIR}/temp/havok_${HAVOK_LIB}_extracted OR NOT ${havok_${HAVOK_LIB}_extracted} EQUAL 0)
 
-    file(GLOB extracted_debug "${debug_dir}/*.o")
-    file(GLOB extracted_release "${release_dir}/*.o")
-    file(GLOB extracted_relwithdebinfo "${relwithdebinfo_dir}/*.o")
+            file(GLOB extracted_debug "${debug_dir}/*.o")
+            file(GLOB extracted_release "${release_dir}/*.o")
+            file(GLOB extracted_relwithdebinfo "${relwithdebinfo_dir}/*.o")
 
     if(DEBUG_PREBUILT)
       MESSAGE(STATUS "extracted_debug ${debug_dir}/*.o")
@@ -123,15 +123,15 @@ foreach(HAVOK_LIB ${HAVOK_LIBS})
       MESSAGE(STATUS "extracted_relwithdebinfo ${relwithdebinfo_dir}/*.o")
     endif(DEBUG_PREBUILT)
 
-    list(APPEND HK_DEBUG_LIBRARIES ${extracted_debug})
-    list(APPEND HK_RELEASE_LIBRARIES ${extracted_release})
-    list(APPEND HK_RELWITHDEBINFO_LIBRARIES ${extracted_relwithdebinfo})
-  else(LINUX)
-  # Win32
-    list(APPEND HK_DEBUG_LIBRARIES   ${HAVOK_DEBUG_LIB_${HAVOK_LIB}})
-    list(APPEND HK_RELEASE_LIBRARIES ${HAVOK_RELEASE_LIB_${HAVOK_LIB}})
-    list(APPEND HK_RELWITHDEBINFO_LIBRARIES ${HAVOK_RELWITHDEBINFO_LIB_${HAVOK_LIB}})
-  endif (LINUX)
+            list(APPEND HK_DEBUG_LIBRARIES ${extracted_debug})
+            list(APPEND HK_RELEASE_LIBRARIES ${extracted_release})
+            list(APPEND HK_RELWITHDEBINFO_LIBRARIES ${extracted_relwithdebinfo})
+        else(LINUX)
+        # Win32
+            list(APPEND HK_DEBUG_LIBRARIES   ${HAVOK_DEBUG_LIB_${HAVOK_LIB}})
+            list(APPEND HK_RELEASE_LIBRARIES ${HAVOK_RELEASE_LIB_${HAVOK_LIB}})
+            list(APPEND HK_RELWITHDEBINFO_LIBRARIES ${HAVOK_RELWITHDEBINFO_LIB_${HAVOK_LIB}})
+        endif (LINUX)
 endforeach(HAVOK_LIB)
 
 endif(NOT DEFINED ${CMAKE_CURRENT_LIST_FILE}_INCLUDED)
diff --git a/indra/cmake/LLPrimitive.cmake b/indra/cmake/LLPrimitive.cmake
index ab39cbb6be88597566dfac2d3c3c256100e44018..0d87ff579a870e41bdc184803f14e545df524b13 100755
--- a/indra/cmake/LLPrimitive.cmake
+++ b/indra/cmake/LLPrimitive.cmake
@@ -2,6 +2,8 @@
 
 # these should be moved to their own cmake file
 include(Prebuilt)
+include(Boost)
+
 use_prebuilt_binary(colladadom)
 use_prebuilt_binary(pcre)
 use_prebuilt_binary(libxml)
@@ -15,10 +17,7 @@ if (WINDOWS)
         optimized llprimitive
         debug libcollada14dom22-d
         optimized libcollada14dom22
-        debug libboost_filesystem-mt-gd
-        optimized libboost_filesystem-mt
-        debug libboost_system-mt-gd
-        optimized libboost_system-mt
+        ${BOOST_SYSTEM_LIBRARIES}
         )
 else (WINDOWS)
     set(LLPRIMITIVE_LIBRARIES 
diff --git a/indra/cmake/LLRender.cmake b/indra/cmake/LLRender.cmake
index ae71ee4c0d611e09cd9e8d98f16bb21ececc4c1d..868922451f0008135f92ce7f97abdea9ef53fcbe 100755
--- a/indra/cmake/LLRender.cmake
+++ b/indra/cmake/LLRender.cmake
@@ -11,8 +11,8 @@ set(LLRENDER_INCLUDE_DIRS
 
 if (BUILD_HEADLESS)
   set(LLRENDER_HEADLESS_LIBRARIES
-    llrenderheadless
-    )
+      llrenderheadless
+      )
 endif (BUILD_HEADLESS)
 set(LLRENDER_LIBRARIES
     llrender
diff --git a/indra/cmake/LLWindow.cmake b/indra/cmake/LLWindow.cmake
index 0def507e659aca39bd2cc67a3f496f55c79e71d2..ad732ef650d71f3707ff224daa75db2064cf8b41 100755
--- a/indra/cmake/LLWindow.cmake
+++ b/indra/cmake/LLWindow.cmake
@@ -33,10 +33,10 @@ set(LLWINDOW_INCLUDE_DIRS
 
 if (BUILD_HEADLESS)
   set(LLWINDOW_HEADLESS_LIBRARIES
-    llwindowheadless
-    )
+      llwindowheadless
+      )
 endif (BUILD_HEADLESS)
 
-set(LLWINDOW_LIBRARIES
-    llwindow
-    )
+  set(LLWINDOW_LIBRARIES
+      llwindow
+      )
diff --git a/indra/cmake/VisualLeakDetector.cmake b/indra/cmake/VisualLeakDetector.cmake
index 27e93e28bb483f85fd9980beb5404f7339babca5..6a20148b47b497ed26a0025839deb35f988b310b 100755
--- a/indra/cmake/VisualLeakDetector.cmake
+++ b/indra/cmake/VisualLeakDetector.cmake
@@ -1,12 +1,12 @@
 # -*- cmake -*-
 
-set(INCLUDE_VLD_CMAKE OFF CACHE BOOL "Build the Windows viewer with Visual Leak Detector turned on or off")
+  set(INCLUDE_VLD_CMAKE OFF CACHE BOOL "Build the Windows viewer with Visual Leak Detector turned on or off")
 
-if (INCLUDE_VLD_CMAKE)
+  if (INCLUDE_VLD_CMAKE)
 
-  if (WINDOWS)
-    add_definitions(-DINCLUDE_VLD=1)
-  endif (WINDOWS)
+    if (WINDOWS)
+      add_definitions(-DINCLUDE_VLD=1)
+    endif (WINDOWS)
 
-endif (INCLUDE_VLD_CMAKE)
+  endif (INCLUDE_VLD_CMAKE)
 
diff --git a/indra/lib/python/indra/util/llversion.py b/indra/lib/python/indra/util/llversion.py
deleted file mode 100755
index ba6f567b607f43792231d18a19857068d587f408..0000000000000000000000000000000000000000
--- a/indra/lib/python/indra/util/llversion.py
+++ /dev/null
@@ -1,107 +0,0 @@
-#!/usr/bin/env python
-"""\
-@file  llversion.py
-@brief Parses llcommon/llversionserver.h and llcommon/llversionviewer.h
-       for the version string and channel string.
-       Parses hg info for branch and revision.
-
-$LicenseInfo:firstyear=2006&license=mit$
-
-Copyright (c) 2006-2009, Linden Research, Inc.
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
-$/LicenseInfo$
-"""
-
-import re, sys, os, subprocess
-
-# Methods for gathering version information from
-# llversionviewer.h and llversionserver.h
-
-def get_src_root():
-    indra_lib_python_indra_path = os.path.dirname(__file__)
-    return os.path.abspath(os.path.realpath(indra_lib_python_indra_path + "/../../../../../"))
-
-def get_version_file_contents(version_type):
-    filepath = get_src_root() + '/indra/llcommon/llversion%s.h' % version_type
-    file = open(filepath,"r")
-    file_str = file.read()
-    file.close()
-    return file_str
-
-def get_version(version_type):
-    file_str = get_version_file_contents(version_type)
-    m = re.search('const S32 LL_VERSION_MAJOR = (\d+);', file_str)
-    VER_MAJOR = m.group(1)
-    m = re.search('const S32 LL_VERSION_MINOR = (\d+);', file_str)
-    VER_MINOR = m.group(1)
-    m = re.search('const S32 LL_VERSION_PATCH = (\d+);', file_str)
-    VER_PATCH = m.group(1)
-    m = re.search('const S32 LL_VERSION_BUILD = (\d+);', file_str)
-    VER_BUILD = m.group(1)
-    version = "%(VER_MAJOR)s.%(VER_MINOR)s.%(VER_PATCH)s.%(VER_BUILD)s" % locals()
-    return version
-
-def get_channel(version_type):
-    file_str = get_version_file_contents(version_type)
-    m = re.search('const char \* const LL_CHANNEL = "(.+)";', file_str)
-    return m.group(1)
-    
-def get_viewer_version():
-    return get_version('viewer')
-
-def get_server_version():
-    return get_version('server')
-
-def get_viewer_channel():
-    return get_channel('viewer')
-
-def get_server_channel():
-    return get_channel('server')
-
-# Methods for gathering hg information
-def get_hg_repo():
-    child = subprocess.Popen(["hg","showconfig","paths.default"], stdout=subprocess.PIPE)
-    output, error = child.communicate()
-    status = child.returncode
-    if status:
-        print >> sys.stderr, error
-        sys.exit(1)
-    if not output:
-        print >> sys.stderr, 'ERROR: cannot find repo we cloned from'
-        sys.exit(1)
-    return output
-
-def get_hg_changeset():
-    # The right thing to do would be to use the *global* revision id:
-    #     "hg id -i"
-    # For the moment though, we use the parent revision:
-    child = subprocess.Popen(["hg","parents","--template","{rev}"], stdout=subprocess.PIPE)
-    output, error = child.communicate()
-    status = child.returncode
-    if status:
-        print >> sys.stderr, error
-        sys.exit(1)
-    lines = output.splitlines()
-    if len(lines) > 1:
-        print >> sys.stderr, 'ERROR: working directory has %d parents' % len(lines)
-    return lines[0]
-
-def using_hg():
-    return os.path.isdir(os.path.join(get_src_root(), '.hg'))
diff --git a/indra/linux_crash_logger/CMakeLists.txt b/indra/linux_crash_logger/CMakeLists.txt
index 41b92b00e0f29d9febfe839bb3402f853baeeb6d..c0fc1b2be0ecce2bceb1b2263c6e29a77c3ca09f 100755
--- a/indra/linux_crash_logger/CMakeLists.txt
+++ b/indra/linux_crash_logger/CMakeLists.txt
@@ -26,6 +26,10 @@ include_directories(SYSTEM
     ${LLCOMMON_SYSTEM_INCLUDE_DIRS}
     ${LLXML_SYSTEM_INCLUDE_DIRS}
     )
+include_directories(SYSTEM
+    ${LLCOMMON_SYSTEM_INCLUDE_DIRS}
+    ${LLXML_SYSTEM_INCLUDE_DIRS}
+    )
 
 set(linux_crash_logger_SOURCE_FILES
     linux_crash_logger.cpp
diff --git a/indra/llappearance/llpolymorph.cpp b/indra/llappearance/llpolymorph.cpp
index 8a178190833ca463c15499e9722cb4e7300ca8af..93c2f15a535e378ffbdc74562d3867b5697123db 100644
--- a/indra/llappearance/llpolymorph.cpp
+++ b/indra/llappearance/llpolymorph.cpp
@@ -597,19 +597,31 @@ void LLPolyMorphTarget::apply( ESex avatar_sex )
 			norm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR);
 			scaled_normals[vert_index_mesh].add(norm);
 			norm = scaled_normals[vert_index_mesh];
+
+			// guard against degenerate input data before we create NaNs below!
+			//
 			norm.normalize3fast();
 			normals[vert_index_mesh] = norm;
 
 			// calculate new binormals
 			LLVector4a binorm = mMorphData->mBinormals[vert_index_morph];
+
+			// guard against degenerate input data before we create NaNs below!
+			//
+			if (!binorm.isFinite3() || (binorm.dot3(binorm).getF32() <= F_APPROXIMATELY_ZERO))
+			{
+				binorm.set(1,0,0,1);
+			}
+
 			binorm.mul(delta_weight*maskWeight*NORMAL_SOFTEN_FACTOR);
 			scaled_binormals[vert_index_mesh].add(binorm);
 			LLVector4a tangent;
 			tangent.setCross3(scaled_binormals[vert_index_mesh], norm);
 			LLVector4a& normalized_binormal = binormals[vert_index_mesh];
-			normalized_binormal.setCross3(norm, tangent); 
+
+			normalized_binormal.setCross3(norm, tangent); 			
 			normalized_binormal.normalize3fast();
-			
+
 			tex_coords[vert_index_mesh] += mMorphData->mTexCoords[vert_index_morph] * delta_weight * maskWeight;
 		}
 
diff --git a/indra/llaudio/llaudioengine_fmodex.cpp b/indra/llaudio/llaudioengine_fmodex.cpp
index 45fc3186f4b281cb56fea4d1f10ea3aecf187692..e9b74b8f41836985fb356e57e0db680c8b284ef3 100644
--- a/indra/llaudio/llaudioengine_fmodex.cpp
+++ b/indra/llaudio/llaudioengine_fmodex.cpp
@@ -67,7 +67,7 @@ inline bool Check_FMOD_Error(FMOD_RESULT result, const char *string)
 {
 	if(result == FMOD_OK)
 		return false;
-	llwarns << string << " Error: " << FMOD_ErrorString(result) << llendl;
+	lldebugs << string << " Error: " << FMOD_ErrorString(result) << llendl;
 	return true;
 }
 
@@ -258,19 +258,29 @@ bool LLAudioEngine_FMODEX::init(const S32 num_channels, void* userdata)
 
 	int r_numbuffers, r_samplerate, r_channels, r_bits;
 	unsigned int r_bufferlength;
-	char r_name[256];
 	mSystem->getDSPBufferSize(&r_bufferlength, &r_numbuffers);
+	LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_bufferlength=" << r_bufferlength << " bytes" << LL_ENDL;
+	LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_numbuffers=" << r_numbuffers << LL_ENDL;
+
 	mSystem->getSoftwareFormat(&r_samplerate, NULL, &r_channels, NULL, NULL, &r_bits);
-	mSystem->getDriverInfo(0, r_name, 255, 0);
-	r_name[255] = '\0';
-	int latency = (int)(1000.0f * r_bufferlength * r_numbuffers / r_samplerate);
+	LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_samplerate=" << r_samplerate << "Hz" << LL_ENDL;
+	LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_channels=" << r_channels << LL_ENDL;
+	LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_bits =" << r_bits << LL_ENDL;
+
+	char r_name[512];
+	mSystem->getDriverInfo(0, r_name, 511, 0);
+	r_name[511] = '\0';
+	LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): r_name=\"" << r_name << "\"" <<  LL_ENDL;
 
-	LL_INFOS("AppInit") << "FMOD device: "<< r_name << "\n"
-		<< "FMOD Ex parameters: " << r_samplerate << " Hz * " << r_channels << " * " <<r_bits <<" bit\n"
-		<< "\tbuffer " << r_bufferlength << " * " << r_numbuffers << " (" << latency <<"ms)" << LL_ENDL;
+	int latency = 100; // optimistic default - i suspect if sample rate is 0, everything breaks. 
+	if ( r_samplerate != 0 )
+		latency = (int)(1000.0f * r_bufferlength * r_numbuffers / r_samplerate);
+	LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): latency=" << latency << "ms" << LL_ENDL;
 
 	mInited = true;
 
+	LL_INFOS("AppInit") << "LLAudioEngine_FMODEX::init(): initialization complete." << LL_ENDL;
+
 	return true;
 }
 
@@ -310,8 +320,8 @@ void LLAudioEngine_FMODEX::shutdown()
 	llinfos << "LLAudioEngine_FMODEX::shutdown() closing FMOD Ex" << llendl;
 	if ( mSystem ) // speculative fix for MAINT-2657
 	{
-		mSystem->close();
-		mSystem->release();
+	mSystem->close();
+	mSystem->release();
 	}
 	llinfos << "LLAudioEngine_FMODEX::shutdown() done closing FMOD Ex" << llendl;
 
diff --git a/indra/llaudio/llwindgen.h b/indra/llaudio/llwindgen.h
index 719b0ecbf24a42a1ebd9e7c2889d598fc7743a63..ec58f76f5fd34c48d824e3cbabac3e794fceb33d 100755
--- a/indra/llaudio/llwindgen.h
+++ b/indra/llaudio/llwindgen.h
@@ -57,7 +57,7 @@ class LLWindGen
 	const U32 getInputSamplingRate() { return mInputSamplingRate; }
 	const F32 getNextSample();
 	const F32 getClampedSample(bool clamp, F32 sample);
-
+	
 	// newbuffer = the buffer passed from the previous DSP unit.
 	// numsamples = length in samples-per-channel at this mix time.
 	// NOTE: generates L/R interleaved stereo
@@ -133,11 +133,11 @@ class LLWindGen
 				MIXBUFFERFORMAT_T	sample_left = (MIXBUFFERFORMAT_T)getClampedSample(clip, mLastSample - (F32)sample_right);
 				
 				*cursamplep = sample_left;
-				++cursamplep;
+					++cursamplep;
 				*cursamplep = sample_right;
-				++cursamplep;
+					++cursamplep;
+				}
 			}
-		}
 		
 		return newbuffer;
 	}
diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp
index c6da205815c8f32a647b09eb140a07cd5f6ba01d..67a98d5fb89d9c85b979be3cf863c9f7e601712d 100755
--- a/indra/llcommon/llapp.cpp
+++ b/indra/llcommon/llapp.cpp
@@ -986,9 +986,9 @@ bool windows_post_minidump_callback(const wchar_t* dump_path,
 	}
 
 	llinfos << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << llendl;
-    // *NOTE:Mani - this code is stolen from LLApp, where its never actually used.
+   // *NOTE:Mani - this code is stolen from LLApp, where its never actually used.
 	//OSMessageBox("Attach Debugger Now", "Error", OSMB_OK);
-    // *TODO: Translate the signals/exceptions into cross-platform stuff
+   // *TODO: Translate the signals/exceptions into cross-platform stuff
 	// Windows implementation
 	llinfos << "Entering Windows Exception Handler..." << llendl;
 
diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp
index d1c44c94032851a19a4ab42f20006ce04a1eb1f4..a0802c6adfe997952e56a84a5477d5f47d1c0143 100755
--- a/indra/llcommon/llapr.cpp
+++ b/indra/llcommon/llapr.cpp
@@ -226,9 +226,7 @@ void LLVolatileAPRPool::clearVolatileAPRPool()
 		llassert_always(mNumActiveRef > 0) ;
 	}
 
-	//paranoia check if the pool is jammed.
-	//will remove the check before going to release.
-	llassert_always(mNumTotalRef < (FULL_VOLATILE_APR_POOL << 2)) ;
+	llassert(mNumTotalRef < (FULL_VOLATILE_APR_POOL << 2)) ;
 }
 
 BOOL LLVolatileAPRPool::isFull()
diff --git a/indra/llcommon/llavatarname.h b/indra/llcommon/llavatarname.h
index 7542a8dece0918da062061d0b10d1441a3198a1d..5d2fccc5bab0ede19a47b9eb10c1bb6c57764930 100755
--- a/indra/llcommon/llavatarname.h
+++ b/indra/llcommon/llavatarname.h
@@ -63,7 +63,7 @@ class LL_COMMON_API LLAvatarName
 	// For normal names, returns "James Linden (james.linden)"
 	// When display names are disabled returns just "James Linden"
 	std::string getCompleteName() const;
-
+	
 	// Returns "James Linden" or "bobsmith123 Resident" for backwards
 	// compatibility with systems like voice and muting
 	// *TODO: Eliminate this in favor of username only
diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp
index a629f71d4b94ee74327774b6f011b9a1fdb2aa9e..baaddcaed1ea64d1cbc425336b84000b55227cd6 100755
--- a/indra/llcommon/llcoros.cpp
+++ b/indra/llcommon/llcoros.cpp
@@ -60,7 +60,7 @@ bool LLCoros::cleanup(const LLSD&)
         // since last tick?
         if (mi->second->exited())
         {
-            LL_INFOS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << LL_ENDL;
+			   LL_INFOS("LLCoros") << "LLCoros: cleaning up coroutine " << mi->first << LL_ENDL;
             // The erase() call will invalidate its passed iterator value --
             // so increment mi FIRST -- but pass its original value to
             // erase(). This is what postincrement is all about.
@@ -94,7 +94,7 @@ std::string LLCoros::generateDistinctName(const std::string& prefix) const
     {
         if (mCoros.find(name) == mCoros.end())
         {
-            LL_INFOS("LLCoros") << "LLCoros: launching coroutine " << name << LL_ENDL;
+			   LL_INFOS("LLCoros") << "LLCoros: launching coroutine " << name << LL_ENDL;
             return name;
         }
     }
diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp
index 9b0141eb76717dc363d90010f46577db8146766b..d2af004cde71a209ae084c0eecd5478f5ab11839 100755
--- a/indra/llcommon/llerror.cpp
+++ b/indra/llcommon/llerror.cpp
@@ -201,10 +201,7 @@ namespace {
 		virtual void recordMessage(LLError::ELevel level,
 								   const std::string& message)
 		{
-			llutf16string utf16str =
-				wstring_to_utf16str(utf8str_to_wstring(message));
-			utf16str += '\n';
-			OutputDebugString(utf16str.c_str());
+			LL_WINDOWS_OUTPUT_DEBUG(message);
 		}
 	};
 #endif
@@ -1401,5 +1398,27 @@ namespace LLError
    {
        sIndex = 0 ;
    }
+
+#if LL_WINDOWS
+	void LLOutputDebugUTF8(const std::string& s)
+	{
+		// Be careful when calling OutputDebugString as it throws DBG_PRINTEXCEPTION_C 
+		// which works just fine under the windows debugger, but can cause users who
+		// have enabled SEHOP exception chain validation to crash due to interactions
+		// between the Win 32-bit exception handling and boost coroutine fiber stacks. BUG-2707
+		//
+		if (IsDebuggerPresent())
+		{
+			// Need UTF16 for Unicode OutputDebugString
+			//
+			if (s.size())
+			{
+				OutputDebugString(utf8str_to_utf16str(s).c_str());
+				OutputDebugString(TEXT("\n"));
+			}
+		}
+	}
+#endif
+
 }
 
diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h
index b65b4101531fb6d42be69dfe6ec4315f0f48acc9..0b723aeb5d00df1565a0852b7ca05e6ea81d40ab 100755
--- a/indra/llcommon/llerror.h
+++ b/indra/llcommon/llerror.h
@@ -34,7 +34,6 @@
 #include "llerrorlegacy.h"
 #include "stdtypes.h"
 
-
 /** Error Logging Facility
 
 	Information for most users:
@@ -199,8 +198,20 @@ namespace LLError
        static void clear() ;
 	   static void end(std::ostringstream* _out) ;
    }; 
+
+#if LL_WINDOWS
+	void LLOutputDebugUTF8(const std::string& s);
+#endif
+
 }
 
+#if LL_WINDOWS
+	// Macro accepting a std::string for display in windows debugging console
+	#define LL_WINDOWS_OUTPUT_DEBUG(a) LLError::LLOutputDebugUTF8(a)
+#else
+	#define LL_WINDOWS_OUTPUT_DEBUG(a)
+#endif
+
 //this is cheaper than llcallstacks if no need to output other variables to call stacks. 
 #define llpushcallstacks LLError::LLCallStacks::push(__FUNCTION__, __LINE__)
 #define llcallstacks \
diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
index 9b15804e97b65998f8457a2e0f9625ae3b8edbe4..024fdd1b4d76ee50d73331ae15ecc94130d069d3 100755
--- a/indra/llcommon/llfasttimer.cpp
+++ b/indra/llcommon/llfasttimer.cpp
@@ -561,7 +561,7 @@ std::vector<LLFastTimer::NamedTimer*>& LLFastTimer::NamedTimer::getChildren()
 	return mChildren;
 }
 
-// static
+//static
 LLFastTimer::NamedTimer& LLFastTimer::NamedTimer::getRootNamedTimer()
 {
         return *NamedTimerFactory::instance().getRootTimer();
diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp
index 864b6e6975632d099f217ececae9a54841e6d116..c3a0f0bfe0492d9a8e931f3dd5097bd47bf58fcc 100755
--- a/indra/llcommon/llfile.cpp
+++ b/indra/llcommon/llfile.cpp
@@ -438,7 +438,7 @@ llstdio_filebuf::int_type llstdio_filebuf::overflow(llstdio_filebuf::int_type __
 				_M_set_buffer(0);
 				__ret = traits_type::not_eof(__c);
 			}
-		}
+	}
 		else if (_M_buf_size > 1)
 		{
 			// Overflow in 'uncommitted' mode: set _M_writing, set
@@ -496,11 +496,11 @@ bool llstdio_filebuf::_convert_to_external(char_type* __ibuf,
 		if (__r == codecvt_base::ok || __r == codecvt_base::partial)
 			__blen = __bend - __buf;
 		else if (__r == codecvt_base::noconv)
-		{
+	{
 			// Same as the always_noconv case above.
 			__buf = reinterpret_cast<char*>(__ibuf);
 			__blen = __ilen;
-		}
+	}
 		else
 			__throw_ios_failure(__N("llstdio_filebuf::_convert_to_external "
 									"conversion error"));
@@ -643,9 +643,9 @@ llstdio_filebuf::int_type llstdio_filebuf::underflow()
 							_M_ext_end, _M_ext_next,
 							this->eback(),
 							this->eback() + __buflen, __iend);
-				}
+}
 				if (__r == codecvt_base::noconv)
-				{
+{
 					size_t __avail = _M_ext_end - _M_ext_buf;
 					__ilen = std::min(__avail, __buflen);
 					traits_type::copy(this->eback(),
@@ -806,15 +806,15 @@ std::streamsize llstdio_filebuf::xsputn(char_type* __s, std::streamsize __n)
 				__ret = fwrite(__buf, 1, __buffill, _M_file.file());
 			}
 			if (__ret == __buffill)
-			{
+	{
 				__ret += fwrite(reinterpret_cast<const char*>(__s), 1,
 								__n, _M_file.file());
-			}
+	}
 			if (__ret == __buffill + __n)
 			{
 				_M_set_buffer(0);
 				_M_writing = true;
-			}
+}
 			if (__ret > __buffill)
 				__ret -= __buffill;
 			else
@@ -848,7 +848,7 @@ llifstream::llifstream() : _M_filebuf(),
 #endif
 
 // explicit
-llifstream::llifstream(const std::string& _Filename, 
+llifstream::llifstream(const std::string& _Filename,
 		ios_base::openmode _Mode) : _M_filebuf(),
 #if LL_WINDOWS
 	std::istream(&_M_filebuf)
@@ -877,7 +877,7 @@ llifstream::llifstream(const char* _Filename,
 	if (_M_filebuf.open(wideName.c_str(), _Mode | ios_base::in) == 0)
 	{
 		_Myios::setstate(ios_base::failbit);
-	}
+}
 }
 #else
 	std::istream()
@@ -951,8 +951,8 @@ void llifstream::close()
 #else
 		this->setstate(ios_base::failbit);
 #endif
+		}
 	}
-}
 
 
 /************** output file stream ********************************/
@@ -1042,7 +1042,7 @@ void llofstream::open(const char* _Filename, ios_base::openmode _Mode)
 #if LL_WINDOWS
 	llutf16string wideName = utf8str_to_utf16str( _Filename );
 	if (_M_filebuf.open( wideName.c_str(), _Mode | ios_base::out) == 0)
-	{
+{
 		_Myios::setstate(ios_base::failbit);
 	}
 	else
diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h
index 9d70db96ea83852d4365cf9f0096454bc2e41cec..d59e68367e8cc9429a15397c506455999314fc1a 100755
--- a/indra/llcommon/llfile.h
+++ b/indra/llcommon/llfile.h
@@ -35,7 +35,7 @@
  * Attempts to mostly mirror the POSIX style IO functions.
  */
 
-typedef FILE LLFILE;
+typedef FILE	LLFILE;
 
 #include <fstream>
 #include <sys/stat.h>
@@ -237,7 +237,7 @@ class LL_COMMON_API llifstream	:	public	std::istream
 			ios_base::openmode _Mode = ios_base::in,
 			//size_t _Size = static_cast<size_t>(BUFSIZ));
 			size_t _Size = static_cast<size_t>(1));
-
+	
 	/**
 	 *  @brief  Create a stream using an open file descriptor.
 	 *  @param  fd    An open file descriptor.
diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp
index cef743a7beab012a31a2b42233da8f33db9588b6..614a2d563656693ec5950a13b5968faa30a80c23 100755
--- a/indra/llcommon/llsdserialize_xml.cpp
+++ b/indra/llcommon/llsdserialize_xml.cpp
@@ -406,7 +406,7 @@ S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data)
 		}
 		if (mEmitErrors)
 		{
-			llinfos << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*) buffer << llendl;
+		llinfos << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*) buffer << llendl;
 		}
 		data = LLSD();
 		return LLSDParser::PARSE_FAILURE;
@@ -487,7 +487,7 @@ S32 LLSDXMLParser::Impl::parseLines(std::istream& input, LLSD& data)
 	{
 		if (mEmitErrors)
 		{
-			llinfos << "LLSDXMLParser::Impl::parseLines: XML_STATUS_ERROR" << llendl;
+		llinfos << "LLSDXMLParser::Impl::parseLines: XML_STATUS_ERROR" << llendl;
 		}
 		return LLSDParser::PARSE_FAILURE;
 	}
diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp
index 6f1e7d46b80d48df010c0afd102aec53719019dd..f188865eb004b7395928773dc715461a31aa862a 100755
--- a/indra/llcommon/tests/llprocess_test.cpp
+++ b/indra/llcommon/tests/llprocess_test.cpp
@@ -969,10 +969,7 @@ namespace tut
                       childout.getline(), "ok");
         // important to get the implicit flush from std::endl
         py.mPy->getWritePipe().get_ostream() << "go" << std::endl;
-        for (i = 0; i < timeout && py.mPy->isRunning() && ! childout.contains("\n"); ++i)
-        {
-            yield();
-        }
+        waitfor(*py.mPy);
         ensure("script never replied", childout.contains("\n"));
         ensure_equals("child didn't ack", childout.getline(), "ack");
         ensure_equals("bad child termination", py.mPy->getStatus().mState, LLProcess::EXITED);
diff --git a/indra/llmath/llvector4a.h b/indra/llmath/llvector4a.h
index 0526793d3a6130cd23857815c58ec0435ea629b8..79d0a44551a607f9ca0d8edcfb39dc0054761999 100755
--- a/indra/llmath/llvector4a.h
+++ b/indra/llmath/llvector4a.h
@@ -46,6 +46,7 @@ class LLRotation;
 // of this writing, July 08, 2010) about getting it implemented before you resort to
 // LLVector3/LLVector4. 
 /////////////////////////////////
+class LLVector4a;
 
 LL_ALIGN_PREFIX(16)
 class LLVector4a
@@ -236,6 +237,11 @@ class LLVector4a
 	// Note that this does not consider zero length vectors!
 	inline void normalize3fast();
 
+	// Normalize this vector with respect to the x, y, and z components only. Accurate only to 10-12 bits of precision. W component is destroyed
+	// Same as above except substitutes default vector contents if the vector is non-finite or degenerate due to zero length.
+	//
+	inline void normalize3fast_checked(LLVector4a* d = 0);
+
 	// Return true if this vector is normalized with respect to x,y,z up to tolerance
 	inline LLBool32 isNormalized3( F32 tolerance = 1e-3 ) const;
 
diff --git a/indra/llmath/llvolume.cpp b/indra/llmath/llvolume.cpp
index 3f06e6b99ed38d493f05416c2354185a1ebf20c4..14cebfe5aa7d85c7ff10b6edf92cdaeee91f3e69 100755
--- a/indra/llmath/llvolume.cpp
+++ b/indra/llmath/llvolume.cpp
@@ -1392,7 +1392,7 @@ void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 en
 	pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t);
 	pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t);
 	pt->mTexT  = t;
-	
+
 	// Twist rotates the path along the x,y plane (I think) - DJS 04/05/02
 	twist.setQuat  (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1);
 	// Rotate the point around the circle's center.
@@ -1446,7 +1446,7 @@ void LLPath::genNGon(const LLPathParams& params, S32 sides, F32 startOff, F32 en
 	pt->mScale.mV[VX] = hole_x * lerp(taper_x_begin, taper_x_end, t);
 	pt->mScale.mV[VY] = hole_y * lerp(taper_y_begin, taper_y_end, t);
 	pt->mTexT  = t;
-	
+
 	// Twist rotates the path along the x,y plane (I think) - DJS 04/05/02
 	twist.setQuat  (lerp(twist_begin,twist_end,t) * 2.f * F_PI - F_PI,0,0,1);
 	// Rotate the point around the circle's center.
@@ -1594,7 +1594,7 @@ BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split,
 			S32 sides = (S32)llfloor(llfloor((MIN_DETAIL_FACES * detail + twist_mag * 3.5f * (detail-0.5f))) * params.getRevolutions());
 
 			if (is_sculpted)
-				sides = sculpt_size;
+				sides = llmax(sculpt_size, 1);
 			
 			genNGon(params, sides);
 		}
@@ -1644,6 +1644,7 @@ BOOL LLPath::generate(const LLPathParams& params, F32 detail, S32 split,
 			mPath[i].mScale.mV[0] = lerp(1,params.getScale().mV[0],t);
 			mPath[i].mScale.mV[1] = lerp(1,params.getScale().mV[1],t);
 			mPath[i].mTexT  = t;
+
 			mPath[i].mRot.setQuat(F_PI * params.getTwist() * t,1,0,0);
 		}
 
@@ -2079,9 +2080,9 @@ void LLVolume::regen()
 	createVolumeFaces();
 }
 
-void LLVolume::genBinormals(S32 face)
+void LLVolume::genTangents(S32 face)
 {
-	mVolumeFaces[face].createBinormals();
+	mVolumeFaces[face].createTangents();
 }
 
 LLVolume::~LLVolume()
@@ -2442,6 +2443,7 @@ bool LLVolume::unpackVolumeFaces(std::istream& is, S32 size)
 			LLVector4a pos_range;
 			pos_range.setSub(max_pos, min_pos);
 			LLVector2 tc_range2 = max_tc - min_tc;
+
 			LLVector4a tc_range;
 			tc_range.set(tc_range2[0], tc_range2[1], tc_range2[0], tc_range2[1]);
 			LLVector4a min_tc4(min_tc[0], min_tc[1], min_tc[0], min_tc[1]);
@@ -4392,7 +4394,7 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
 				segments.push_back(vertices.size());
 #if DEBUG_SILHOUETTE_BINORMALS
 				vertices.push_back(face.mVertices[j].getPosition());
-				vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].mBinormal*0.1f);
+				vertices.push_back(face.mVertices[j].getPosition() + face.mVertices[j].mTangent*0.1f);
 				normals.push_back(LLVector3(0,0,1));
 				normals.push_back(LLVector3(0,0,1));
 				segments.push_back(vertices.size());
@@ -4508,22 +4510,9 @@ void LLVolume::generateSilhouetteVertices(std::vector<LLVector3> &vertices,
 	}
 }
 
-S32 LLVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, 
-								   S32 face,
-								   LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
-{
-	LLVector4a starta, enda;
-	starta.load3(start.mV);
-	enda.load3(end.mV);
-
-	return lineSegmentIntersect(starta, enda, face, intersection, tex_coord, normal, bi_normal);
-
-}
-
-
 S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, 
 								   S32 face,
-								   LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
+								   LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent_out)
 {
 	S32 hit_face = -1;
 	
@@ -4561,9 +4550,9 @@ S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& en
 
         if (LLLineSegmentBoxIntersect(start, end, box_center, box_size))
 		{
-			if (bi_normal != NULL) // if the caller wants binormals, we may need to generate them
+			if (tangent_out != NULL) // if the caller wants tangents, we may need to generate them
 			{
-				genBinormals(i);
+				genTangents(i);
 			}
 
 			if (isUnique())
@@ -4597,7 +4586,7 @@ S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& en
 								LLVector4a intersect = dir;
 								intersect.mul(closest_t);
 								intersect.add(start);
-								intersection->set(intersect.getF32ptr());
+								*intersection = intersect;
 							}
 
 
@@ -4612,19 +4601,42 @@ S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& en
 
 							if (normal!= NULL)
 							{
-								LLVector4* norm = (LLVector4*) face.mNormals;
-
-								*normal		= ((1.f - a - b)  * LLVector3(norm[idx0]) + 
-									a              * LLVector3(norm[idx1]) +
-									b              * LLVector3(norm[idx2]));
+								LLVector4a* norm = face.mNormals;
+								
+								LLVector4a n1,n2,n3;
+								n1 = norm[idx0];
+								n1.mul(1.f-a-b);
+								
+								n2 = norm[idx1];
+								n2.mul(a);
+								
+								n3 = norm[idx2];
+								n3.mul(b);
+
+								n1.add(n2);
+								n1.add(n3);
+								
+								*normal		= n1; 
 							}
 
-							if (bi_normal != NULL)
+							if (tangent_out != NULL)
 							{
-								LLVector4* binormal = (LLVector4*) face.mBinormals;
-								*bi_normal = ((1.f - a - b)  * LLVector3(binormal[idx0]) + 
-										a              * LLVector3(binormal[idx1]) +
-										b              * LLVector3(binormal[idx2]));
+								LLVector4a* tangents = face.mTangents;
+								
+								LLVector4a t1,t2,t3;
+								t1 = tangents[idx0];
+								t1.mul(1.f-a-b);
+								
+								t2 = tangents[idx1];
+								t2.mul(a);
+								
+								t3 = tangents[idx2];
+								t3.mul(b);
+
+								t1.add(t2);
+								t1.add(t3);
+								
+								*tangent_out = t1; 
 							}
 						}
 					}
@@ -4637,7 +4649,7 @@ S32 LLVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& en
 					face.createOctree();
 				}
 			
-				LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, bi_normal);
+				LLOctreeTriangleRayIntersect intersect(start, dir, &face, &closest_t, intersection, tex_coord, normal, tangent_out);
 				intersect.traverse(face.mOctree);
 				if (intersect.mHitFace)
 				{
@@ -5183,7 +5195,7 @@ LLVolumeFace::LLVolumeFace() :
 	mNumIndices(0),
 	mPositions(NULL),
 	mNormals(NULL),
-	mBinormals(NULL),
+	mTangents(NULL),
 	mTexCoords(NULL),
 	mIndices(NULL),
 	mWeights(NULL),
@@ -5206,7 +5218,7 @@ LLVolumeFace::LLVolumeFace(const LLVolumeFace& src)
 	mNumIndices(0),
 	mPositions(NULL),
 	mNormals(NULL),
-	mBinormals(NULL),
+	mTangents(NULL),
 	mTexCoords(NULL),
 	mIndices(NULL),
 	mWeights(NULL),
@@ -5264,15 +5276,15 @@ LLVolumeFace& LLVolumeFace::operator=(const LLVolumeFace& src)
 		}
 
 
-		if (src.mBinormals)
+		if (src.mTangents)
 		{
-			allocateBinormals(src.mNumVertices);
-			LLVector4a::memcpyNonAliased16((F32*) mBinormals, (F32*) src.mBinormals, vert_size);
+			allocateTangents(src.mNumVertices);
+			LLVector4a::memcpyNonAliased16((F32*) mTangents, (F32*) src.mTangents, vert_size);
 		}
 		else
 		{
-			ll_aligned_free_16(mBinormals);
-			mBinormals = NULL;
+			ll_aligned_free_16(mTangents);
+			mTangents = NULL;
 		}
 
 		if (src.mWeights)
@@ -5316,8 +5328,8 @@ void LLVolumeFace::freeData()
 	mTexCoords = NULL;
 	ll_aligned_free_16(mIndices);
 	mIndices = NULL;
-	ll_aligned_free_16(mBinormals);
-	mBinormals = NULL;
+	ll_aligned_free_16(mTangents);
+	mTangents = NULL;
 	ll_aligned_free_16(mWeights);
 	mWeights = NULL;
 
@@ -5897,7 +5909,7 @@ void LLVolumeFace::cacheOptimize()
 	}
 
 	LLVector4a* binorm = NULL;
-	if (mBinormals)
+	if (mTangents)
 	{
 		binorm = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
 	}
@@ -5922,9 +5934,9 @@ void LLVolumeFace::cacheOptimize()
 			{
 				wght[cur_idx] = mWeights[idx];
 			}
-			if (mBinormals)
+			if (mTangents)
 			{
-				binorm[cur_idx] = mBinormals[idx];
+				binorm[cur_idx] = mTangents[idx];
 			}
 
 			cur_idx++;
@@ -5940,13 +5952,13 @@ void LLVolumeFace::cacheOptimize()
 	ll_aligned_free_16(mNormals);
 	ll_aligned_free_16(mTexCoords);
 	ll_aligned_free_16(mWeights);
-	ll_aligned_free_16(mBinormals);
+	ll_aligned_free_16(mTangents);
 
 	mPositions = pos;
 	mNormals = norm;
 	mTexCoords = tc;
 	mWeights = wght;
-	mBinormals = binorm;
+	mTangents = binorm;
 
 	//std::string result = llformat("ACMR pre/post: %.3f/%.3f  --  %d triangles %d breaks", pre_acmr, post_acmr, mNumIndices/3, breaks);
 	//llinfos << result << llendl;
@@ -6027,7 +6039,7 @@ void LLVolumeFace::swapData(LLVolumeFace& rhs)
 {
 	llswap(rhs.mPositions, mPositions);
 	llswap(rhs.mNormals, mNormals);
-	llswap(rhs.mBinormals, mBinormals);
+	llswap(rhs.mTangents, mTangents);
 	llswap(rhs.mTexCoords, mTexCoords);
 	llswap(rhs.mIndices,mIndices);
 	llswap(rhs.mNumVertices, mNumVertices);
@@ -6116,22 +6128,11 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
 			corners[2].mTexCoord=swap;
 		}
 
-		LLVector4a binormal;
-		
-		calc_binormal_from_triangle( binormal,
-			corners[0].getPosition(), corners[0].mTexCoord,
-			corners[1].getPosition(), corners[1].mTexCoord,
-			corners[2].getPosition(), corners[2].mTexCoord);
-		
-		binormal.normalize3fast();
-
 		S32 size = (grid_size+1)*(grid_size+1);
 		resizeVertices(size);
-		allocateBinormals(size);
-
+		
 		LLVector4a* pos = (LLVector4a*) mPositions;
 		LLVector4a* norm = (LLVector4a*) mNormals;
-		LLVector4a* binorm = (LLVector4a*) mBinormals;
 		LLVector2* tc = (LLVector2*) mTexCoords;
 
 		for(int gx = 0;gx<grid_size+1;gx++)
@@ -6150,8 +6151,7 @@ BOOL LLVolumeFace::createUnCutCubeCap(LLVolume* volume, BOOL partial_build)
 				*pos++ = newVert.getPosition();
 				*norm++ = baseVert.getNormal();
 				*tc++ = newVert.mTexCoord;
-				*binorm++ = binormal;
-
+				
 				if (gx == 0 && gy == 0)
 				{
 					min = newVert.getPosition();
@@ -6227,8 +6227,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 	if (!(mTypeMask & HOLLOW_MASK) && !(mTypeMask & OPEN_MASK))
 	{
 		resizeVertices(num_vertices+1);
-		allocateBinormals(num_vertices+1);	
-
+		
 		if (!partial_build)
 		{
 			resizeIndices(num_indices+3);
@@ -6237,8 +6236,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 	else
 	{
 		resizeVertices(num_vertices);
-		allocateBinormals(num_vertices);
-
+		
 		if (!partial_build)
 		{
 			resizeIndices(num_indices);
@@ -6272,8 +6270,7 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 	LLVector2* tc = (LLVector2*) mTexCoords;
 	LLVector4a* pos = (LLVector4a*) mPositions;
 	LLVector4a* norm = (LLVector4a*) mNormals;
-	LLVector4a* binorm = (LLVector4a*) mBinormals;
-
+	
 	// Copy the vertices into the array
 	for (S32 i = 0; i < num_vertices; i++)
 	{
@@ -6309,31 +6306,6 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 
 	cuv = (min_uv + max_uv)*0.5f;
 
-	LLVector4a binormal;
-	calc_binormal_from_triangle(binormal,
-		*mCenter, cuv,
-		pos[0], tc[0],
-		pos[1], tc[1]);
-	binormal.normalize3fast();
-
-	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();
-
 	VertexData vd;
 	vd.setPosition(*mCenter);
 	vd.mTexCoord = cuv;
@@ -6342,15 +6314,10 @@ BOOL LLVolumeFace::createCap(LLVolume* volume, BOOL partial_build)
 	{
 		pos[num_vertices] = *mCenter;
 		tc[num_vertices] = cuv;
+
 		num_vertices++;
 	}
 		
-	for (S32 i = 0; i < num_vertices; i++)
-	{
-		binorm[i].load4a(binormal.getF32ptr());
-		norm[i].load4a(normal.getF32ptr());
-	}
-
 	if (partial_build)
 	{
 		return TRUE;
@@ -6585,63 +6552,68 @@ 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;
 }
 
-void LLVolumeFace::createBinormals()
+void CalculateTangentArray(U32 vertexCount, const LLVector4a *vertex, const LLVector4a *normal,
+        const LLVector2 *texcoord, U32 triangleCount, const U16* index_array, LLVector4a *tangent);
+
+void LLVolumeFace::createTangents()
 {
-	if (!mBinormals)
+	if (!mTangents)
 	{
-		allocateBinormals(mNumVertices);
+		allocateTangents(mNumVertices);
 
-		//generate binormals
-		LLVector4a* pos = mPositions;
-		LLVector2* tc = (LLVector2*) mTexCoords;
-		LLVector4a* binorm = (LLVector4a*) mBinormals;
+		//generate tangents
+		//LLVector4a* pos = mPositions;
+		//LLVector2* tc = (LLVector2*) mTexCoords;
+		LLVector4a* binorm = (LLVector4a*) mTangents;
 
-		LLVector4a* end = mBinormals+mNumVertices;
+		LLVector4a* end = mTangents+mNumVertices;
 		while (binorm < end)
 		{
 			(*binorm++).clear();
 		}
 
-		binorm = mBinormals;
-
-		for (U32 i = 0; i < mNumIndices/3; i++) 
-		{	//for each triangle
-			const U16& i0 = mIndices[i*3+0];
-			const U16& i1 = mIndices[i*3+1];
-			const U16& i2 = mIndices[i*3+2];
-						
-			//calculate binormal
-			LLVector4a binormal;
-			calc_binormal_from_triangle(binormal,
-										pos[i0], tc[i0],
-										pos[i1], tc[i1],
-										pos[i2], tc[i2]);
-
+		binorm = mTangents;
 
-			//add triangle normal to vertices
-			binorm[i0].add(binormal);
-			binorm[i1].add(binormal);
-			binorm[i2].add(binormal);
+		CalculateTangentArray(mNumVertices, mPositions, mNormals, mTexCoords, mNumIndices/3, mIndices, mTangents);
 
-			//even out quad contributions
-			if (i % 2 == 0) 
-			{
-				binorm[i2].add(binormal);
-			}
-			else 
-			{
-				binorm[i1].add(binormal);
-			}
-		}
-
-		//normalize binormals
+		//normalize tangents
 		for (U32 i = 0; i < mNumVertices; i++) 
 		{
-			binorm[i].normalize3fast();
+			//binorm[i].normalize3fast();
 			//bump map/planar projection code requires normals to be normalized
 			mNormals[i].normalize3fast();
 		}
@@ -6652,10 +6624,10 @@ void LLVolumeFace::resizeVertices(S32 num_verts)
 {
 	ll_aligned_free_16(mPositions);
 	ll_aligned_free_16(mNormals);
-	ll_aligned_free_16(mBinormals);
+	ll_aligned_free_16(mTangents);
 	ll_aligned_free_16(mTexCoords);
 
-	mBinormals = NULL;
+	mTangents = NULL;
 
 	if (num_verts)
 	{
@@ -6705,9 +6677,9 @@ void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, con
 	ll_assert_aligned(mTexCoords,16);
 	
 
-	//just clear binormals
-	ll_aligned_free_16(mBinormals);
-	mBinormals = NULL;
+	//just clear tangents
+	ll_aligned_free_16(mTangents);
+	mTangents = NULL;
 
 	mPositions[mNumVertices] = pos;
 	mNormals[mNumVertices] = norm;
@@ -6716,10 +6688,10 @@ void LLVolumeFace::pushVertex(const LLVector4a& pos, const LLVector4a& norm, con
 	mNumVertices++;	
 }
 
-void LLVolumeFace::allocateBinormals(S32 num_verts)
+void LLVolumeFace::allocateTangents(S32 num_verts)
 {
-	ll_aligned_free_16(mBinormals);
-	mBinormals = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
+	ll_aligned_free_16(mTangents);
+	mTangents = (LLVector4a*) ll_aligned_malloc_16(sizeof(LLVector4a)*num_verts);
 }
 
 void LLVolumeFace::allocateWeights(S32 num_verts)
@@ -6956,7 +6928,6 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 
 			if ((mTypeMask & INNER_MASK) && (mTypeMask & FLAT_MASK) && mNumS > 2 && s > 0)
 			{
-
 				pos[cur_vertex].load3(mesh[i].mPos.mV);
 				tc[cur_vertex] = LLVector2(ss,tt);
 			
@@ -6987,7 +6958,6 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 		}
 	}
 	
-
 	//get bounding box for this side
 	LLVector4a& face_min = mExtents[0];
 	LLVector4a& face_max = mExtents[1];
@@ -7093,6 +7063,14 @@ BOOL LLVolumeFace::createSide(LLVolume* volume, BOOL partial_build)
 		n[1]->add(c);
 		n[2]->add(c);
 		
+		llassert(llfinite(c.getF32ptr()[0]));
+		llassert(llfinite(c.getF32ptr()[1]));
+		llassert(llfinite(c.getF32ptr()[2]));
+
+		llassert(!llisnan(c.getF32ptr()[0]));
+		llassert(!llisnan(c.getF32ptr()[1]));
+		llassert(!llisnan(c.getF32ptr()[2]));
+
 		//even out quad contributions
 		n[i%2+1]->add(c);
 	}
@@ -7231,53 +7209,101 @@ 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);
+//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;
+
+	memset(tan1, 0, vertexCount*2*sizeof(LLVector4a));
+        
+    for (U32 a = 0; a < triangleCount; a++)
+    {
+        U32 i1 = *index_array++;
+        U32 i2 = *index_array++;
+        U32 i3 = *index_array++;
+        
+        const LLVector4a& v1 = vertex[i1];
+        const LLVector4a& v2 = vertex[i2];
+        const LLVector4a& v3 = vertex[i3];
+        
+        const LLVector2& w1 = texcoord[i1];
+        const LLVector2& w2 = texcoord[i2];
+        const LLVector2& w3 = texcoord[i3];
+        
+		const F32* v1ptr = v1.getF32ptr();
+		const F32* v2ptr = v2.getF32ptr();
+		const F32* v3ptr = v3.getF32ptr();
 		
-	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);
+        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);
+        
+		tan1[i1].add(sdir);
+		tan1[i2].add(sdir);
+		tan1[i3].add(sdir);
+        
+		tan2[i1].add(tdir);
+		tan2[i2].add(tdir);
+		tan2[i3].add(tdir);
+    }
+    
+    for (U32 a = 0; a < vertexCount; a++)
+    {
+        LLVector4a n = normal[a];
+
+		const LLVector4a& t = tan1[a];
+
+		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();
+		
+			// Calculate handedness
+			F32 handedness = ncrosst.dot3(tan2[a]).getF32() < 0.f ? -1.f : 1.f;
+		
+			tsubn.getF32ptr()[3] = handedness;
 
-	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 );
-	}
+			tangent[a] = tsubn;
+		}
+		else
+		{ //degenerate, make up a value
+			tangent[a].set(0,0,1,1);
+		}
+    }
+    
+	ll_aligned_free_16(tan1);
 }
+
+
diff --git a/indra/llmath/llvolume.h b/indra/llmath/llvolume.h
index c845556557bf54ce19fba3737271b003190b6e68..164b8d6652591b356dd03f6c1c9bc1656e46b3fd 100755
--- a/indra/llmath/llvolume.h
+++ b/indra/llmath/llvolume.h
@@ -844,12 +844,12 @@ class LLVolumeFace
 public:
 
 	BOOL create(LLVolume* volume, BOOL partial_build = FALSE);
-	void createBinormals();
+	void createTangents();
 	
 	void appendFace(const LLVolumeFace& face, LLMatrix4& transform, LLMatrix4& normal_tranform);
 
 	void resizeVertices(S32 num_verts);
-	void allocateBinormals(S32 num_verts);
+	void allocateTangents(S32 num_verts);
 	void allocateWeights(S32 num_verts);
 	void resizeIndices(S32 num_indices);
 	void fillFromLegacyData(std::vector<LLVolumeFace::VertexData>& v, std::vector<U16>& idx);
@@ -916,7 +916,7 @@ class LLVolumeFace
 
 	LLVector4a* mPositions;
 	LLVector4a* mNormals;
-	LLVector4a* mBinormals;
+	LLVector4a* mTangents;
 	LLVector2*  mTexCoords;
 	U16* mIndices;
 
@@ -980,7 +980,7 @@ class LLVolume : public LLRefCount
 	void setDirty() { mPathp->setDirty(); mProfilep->setDirty(); }
 
 	void regen();
-	void genBinormals(S32 face);
+	void genTangents(S32 face);
 
 	BOOL isConvex() const;
 	BOOL isCap(S32 face);
@@ -1008,21 +1008,14 @@ class LLVolume : public LLRefCount
 	//get the face index of the face that intersects with the given line segment at the point 
 	//closest to start.  Moves end to the point of intersection.  Returns -1 if no intersection.
 	//Line segment must be in volume space.
-	S32 lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
+	S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
 							 S32 face = -1,                          // which face to check, -1 = ALL_SIDES
-							 LLVector3* intersection = NULL,         // return the intersection point
+							 LLVector4a* intersection = NULL,         // return the intersection point
 							 LLVector2* tex_coord = NULL,            // return the texture coordinates of the intersection point
-							 LLVector3* normal = NULL,               // return the surface normal at the intersection point
-							 LLVector3* bi_normal = NULL             // return the surface bi-normal at the intersection point
+							 LLVector4a* normal = NULL,               // return the surface normal at the intersection point
+							 LLVector4a* tangent = NULL             // return the surface tangent at the intersection point
 		);
 
-	S32 lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, 
-								   S32 face = 1,
-								   LLVector3* intersection = NULL,
-								   LLVector2* tex_coord = NULL,
-								   LLVector3* normal = NULL,
-								   LLVector3* bi_normal = NULL);
-	
 	LLFaceID generateFaceMask();
 
 	BOOL isFaceMaskValid(LLFaceID face_mask);
@@ -1081,21 +1074,12 @@ class LLVolume : public LLRefCount
 
 std::ostream& operator<<(std::ostream &s, const LLVolumeParams &volume_params);
 
-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);
-
 BOOL LLLineSegmentBoxIntersect(const F32* start, const F32* end, const F32* center, const F32* size);
 BOOL LLLineSegmentBoxIntersect(const LLVector3& start, const LLVector3& end, const LLVector3& center, const LLVector3& size);
 BOOL LLLineSegmentBoxIntersect(const LLVector4a& start, const LLVector4a& end, const LLVector4a& center, const LLVector4a& size);
 
-BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
-							F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided);
+//BOOL LLTriangleRayIntersect(const LLVector3& vert0, const LLVector3& vert1, const LLVector3& vert2, const LLVector3& orig, const LLVector3& dir,
+//							F32& intersection_a, F32& intersection_b, F32& intersection_t, BOOL two_sided);
 
 BOOL LLTriangleRayIntersect(const LLVector4a& vert0, const LLVector4a& vert1, const LLVector4a& vert2, const LLVector4a& orig, const LLVector4a& dir,
 							F32& intersection_a, F32& intersection_b, F32& intersection_t);
diff --git a/indra/llmath/llvolumeoctree.cpp b/indra/llmath/llvolumeoctree.cpp
index cc83cb7235868bc4102f219806583c9b9e5e30a7..0728b49c1fd3c345afac128028ad036e22454962 100755
--- a/indra/llmath/llvolumeoctree.cpp
+++ b/indra/llmath/llvolumeoctree.cpp
@@ -94,14 +94,14 @@ void LLVolumeOctreeListener::handleChildAddition(const LLOctreeNode<LLVolumeTria
 
 LLOctreeTriangleRayIntersect::LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir, 
 							   const LLVolumeFace* face, F32* closest_t,
-							   LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
+							   LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent)
    : mFace(face),
      mStart(start),
 	 mDir(dir),
 	 mIntersection(intersection),
 	 mTexCoord(tex_coord),
 	 mNormal(normal),
-	 mBinormal(bi_normal),
+	 mTangent(tangent),
 	 mClosestT(closest_t),
 	 mHitFace(false)
 {
@@ -112,13 +112,7 @@ void LLOctreeTriangleRayIntersect::traverse(const LLOctreeNode<LLVolumeTriangle>
 {
 	LLVolumeOctreeListener* vl = (LLVolumeOctreeListener*) node->getListener(0);
 
-	/*const F32* start = mStart.getF32();
-	const F32* end = mEnd.getF32();
-	const F32* center = vl->mBounds[0].getF32();
-	const F32* size = vl->mBounds[1].getF32();*/
-
-	//if (LLLineSegmentBoxIntersect(mStart, mEnd, vl->mBounds[0], vl->mBounds[1]))
-	if (LLLineSegmentBoxIntersect(mStart.getF32ptr(), mEnd.getF32ptr(), vl->mBounds[0].getF32ptr(), vl->mBounds[1].getF32ptr()))
+	if (LLLineSegmentBoxIntersect(mStart, mEnd, vl->mBounds[0], vl->mBounds[1]))
 	{
 		node->accept(this);
 		for (S32 i = 0; i < node->getChildCount(); ++i)
@@ -152,34 +146,60 @@ void LLOctreeTriangleRayIntersect::visit(const LLOctreeNode<LLVolumeTriangle>* n
 					LLVector4a intersect = mDir;
 					intersect.mul(*mClosestT);
 					intersect.add(mStart);
-					mIntersection->set(intersect.getF32ptr());
+					*mIntersection = intersect;
 				}
 
+				U32 idx0 = tri->mIndex[0];
+				U32 idx1 = tri->mIndex[1];
+				U32 idx2 = tri->mIndex[2];
 
 				if (mTexCoord != NULL)
 				{
 					LLVector2* tc = (LLVector2*) mFace->mTexCoords;
-					*mTexCoord = ((1.f - a - b)  * tc[tri->mIndex[0]] +
-						a              * tc[tri->mIndex[1]] +
-						b              * tc[tri->mIndex[2]]);
+					*mTexCoord = ((1.f - a - b)  * tc[idx0] +
+						a              * tc[idx1] +
+						b              * tc[idx2]);
 
 				}
 
 				if (mNormal != NULL)
 				{
-					LLVector4* norm = (LLVector4*) mFace->mNormals;
-
-					*mNormal    = ((1.f - a - b)  * LLVector3(norm[tri->mIndex[0]]) + 
-						a              * LLVector3(norm[tri->mIndex[1]]) +
-						b              * LLVector3(norm[tri->mIndex[2]]));
+					LLVector4a* norm = mFace->mNormals;
+								
+					LLVector4a n1,n2,n3;
+					n1 = norm[idx0];
+					n1.mul(1.f-a-b);
+								
+					n2 = norm[idx1];
+					n2.mul(a);
+								
+					n3 = norm[idx2];
+					n3.mul(b);
+
+					n1.add(n2);
+					n1.add(n3);
+								
+					*mNormal		= n1; 
 				}
 
-				if (mBinormal != NULL)
+				if (mTangent != NULL)
 				{
-					LLVector4* binormal = (LLVector4*) mFace->mBinormals;
-					*mBinormal = ((1.f - a - b)  * LLVector3(binormal[tri->mIndex[0]]) + 
-							a              * LLVector3(binormal[tri->mIndex[1]]) +
-							b              * LLVector3(binormal[tri->mIndex[2]]));
+					LLVector4a* tangents = mFace->mTangents;
+								
+					LLVector4a t1,t2,t3;
+					t1 = tangents[idx0];
+					t1.mul(1.f-a-b);
+								
+					t2 = tangents[idx1];
+					t2.mul(a);
+								
+					t3 = tangents[idx2];
+					t3.mul(b);
+
+					t1.add(t2);
+					t1.add(t3);
+								
+					*mTangent = t1; 
 				}
 			}
 		}
diff --git a/indra/llmath/llvolumeoctree.h b/indra/llmath/llvolumeoctree.h
index 9ae34a0c4e65cb551a67c9802233c16cf6af2818..80d6ced36db8333799148a7a9de3ca971a886869 100755
--- a/indra/llmath/llvolumeoctree.h
+++ b/indra/llmath/llvolumeoctree.h
@@ -137,16 +137,16 @@ class LLOctreeTriangleRayIntersect : public LLOctreeTraveler<LLVolumeTriangle>
 	LLVector4a mStart;
 	LLVector4a mDir;
 	LLVector4a mEnd;
-	LLVector3* mIntersection;
+	LLVector4a* mIntersection;
 	LLVector2* mTexCoord;
-	LLVector3* mNormal;
-	LLVector3* mBinormal;
+	LLVector4a* mNormal;
+	LLVector4a* mTangent;
 	F32* mClosestT;
 	bool mHitFace;
 
 	LLOctreeTriangleRayIntersect(const LLVector4a& start, const LLVector4a& dir, 
 								   const LLVolumeFace* face, F32* closest_t,
-								   LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal);
+								   LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent);
 
 	void traverse(const LLOctreeNode<LLVolumeTriangle>* node);
 
diff --git a/indra/llmessage/CMakeLists.txt b/indra/llmessage/CMakeLists.txt
index 1a90c32fe4fd0ee38433164a7e7a0d59ddfb885a..d193e367eb61fe7631d7c5b265eadf623d71e480 100755
--- a/indra/llmessage/CMakeLists.txt
+++ b/indra/llmessage/CMakeLists.txt
@@ -246,7 +246,7 @@ if (LL_TESTS)
     ${LLVFS_LIBRARIES}
     ${LLMATH_LIBRARIES}
     ${LLCOMMON_LIBRARIES}
-    ${GOOGLEMOCK_LIBRARIES}
+      ${GOOGLEMOCK_LIBRARIES}
     )
 
   LL_ADD_INTEGRATION_TEST(
diff --git a/indra/llmessage/llares.cpp b/indra/llmessage/llares.cpp
index 5a67035ed15fff56a9d42742c26c74dee8b36f4f..7f74247a137d141450345c2e2da9d70f9e08af51 100755
--- a/indra/llmessage/llares.cpp
+++ b/indra/llmessage/llares.cpp
@@ -99,8 +99,7 @@ void LLAres::QueryResponder::queryError(int code)
 
 LLAres::LLAres() :
     chan_(NULL),
-    mInitSuccess(false),
-    mListener(new LLAresListener(this))
+    mInitSuccess(false)
 {
 	if (ares_library_init( ARES_LIB_INIT_ALL ) != ARES_SUCCESS ||
 		ares_init(&chan_) != ARES_SUCCESS)
@@ -109,6 +108,8 @@ LLAres::LLAres() :
 		return;
 	}
 
+	mListener = boost::shared_ptr< LLAresListener >(new LLAresListener(this));
+
 	mInitSuccess = true;
 }
 
@@ -161,12 +162,26 @@ void LLAres::getSrvRecords(const std::string &name, SrvResponder *resp)
 }
 	
 void LLAres::rewriteURI(const std::string &uri, UriRewriteResponder *resp)
-{
-	llinfos << "Rewriting " << uri << llendl;
+{	
+	if (resp && uri.size())
+	{
+		LLURI* pURI = new LLURI(uri);
+
+		resp->mUri = *pURI;
+
+		delete pURI;
+
+		if (!resp->mUri.scheme().size() || !resp->mUri.hostName().size())
+		{
+			return;
+		}
+
+		//llinfos << "LLAres::rewriteURI (" << uri << ") search: '" << "_" + resp->mUri.scheme() + "._tcp." + resp->mUri.hostName() << "'" << llendl;
 
-	resp->mUri = LLURI(uri);
-	search("_" + resp->mUri.scheme() + "._tcp." + resp->mUri.hostName(),
-		   RES_SRV, resp);
+		search("_" + resp->mUri.scheme() + "._tcp." + resp->mUri.hostName(), RES_SRV, resp);
+
+		
+	}
 }
 
 LLQueryResponder::LLQueryResponder()
diff --git a/indra/llmessage/llareslistener.cpp b/indra/llmessage/llareslistener.cpp
index 58b8a05a9e42d059d52611d63118efec2049c4b6..0a4effac19a36920a15872cf49558dead47a1587 100755
--- a/indra/llmessage/llareslistener.cpp
+++ b/indra/llmessage/llareslistener.cpp
@@ -93,5 +93,12 @@ class UriRewriteResponder: public LLAres::UriRewriteResponder
 
 void LLAresListener::rewriteURI(const LLSD& data)
 {
-    mAres->rewriteURI(data["uri"], new UriRewriteResponder(data));
+	if (mAres)
+	{
+		mAres->rewriteURI(data["uri"], new UriRewriteResponder(data));
+	}
+	else
+	{
+		llinfos << "LLAresListener::rewriteURI requested without Ares present. Ignoring: " << data << llendl;
+	}
 }
diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp
index 3561459bb40f28da675fed5bb755aa4d3eb83af9..6110b035dce4d2286f879e63cf0879d565a340a5 100755
--- a/indra/llmessage/llhttpclient.cpp
+++ b/indra/llmessage/llhttpclient.cpp
@@ -224,7 +224,7 @@ static void request(
 	{
 		if (responder)
 		{
-			responder->completed(U32_MAX, "No pump", LLSD());
+		responder->completed(U32_MAX, "No pump", LLSD());
 		}
 		delete body_injector;
 		return;
@@ -238,9 +238,9 @@ static void request(
 		{
 			responder->completed(498, "Internal Error - curl failure", LLSD());
 		}
-		delete req;
+		delete req ;
 		delete body_injector;
-		return;
+		return ;
 	}
 
 	req->setSSLVerifyCallback(LLHTTPClient::getCertVerifyCallback(), (void *)req);
diff --git a/indra/llmessage/llhttpclientadapter.cpp b/indra/llmessage/llhttpclientadapter.cpp
index 0b59209af1b6d1efea5e01150b4d92fcd29ac6bf..dcd2d79d67ef1646552bca319768ab1ce2ab7d2b 100755
--- a/indra/llmessage/llhttpclientadapter.cpp
+++ b/indra/llmessage/llhttpclientadapter.cpp
@@ -45,8 +45,8 @@ void LLHTTPClientAdapter::get(const std::string& url, LLCurl::ResponderPtr respo
 	LLSD empty_pragma_header = headers;
 	if (!empty_pragma_header.has("Pragma"))
 	{
-		// as above
-		empty_pragma_header["Pragma"] = " ";
+	// as above
+	empty_pragma_header["Pragma"] = " ";
 	}
 	LLHTTPClient::get(url, responder, empty_pragma_header);
 }
diff --git a/indra/llmessage/llurlrequest.cpp b/indra/llmessage/llurlrequest.cpp
index 627d5918392f94b9d307890d6e225d57dbbbab00..de9e2fe29472ee0e8d12d2114fca6e7928e27ca3 100755
--- a/indra/llmessage/llurlrequest.cpp
+++ b/indra/llmessage/llurlrequest.cpp
@@ -314,11 +314,11 @@ LLIOPipe::EStatus LLURLRequest::process_impl(
 		 const F32 TIMEOUT_ADJUSTMENT = 2.0f;
 		 mDetail->mByteAccumulator = 0;
 		 pump->adjustTimeoutSeconds(TIMEOUT_ADJUSTMENT);
-		 lldebugs << "LLURLRequest adjustTimeoutSeconds for request: " << mDetail->mURL << llendl;
-		 if (mState == STATE_INITIALIZED)
-		 {
-			  llinfos << "LLURLRequest adjustTimeoutSeconds called during upload" << llendl;
-		 }
+		lldebugs << "LLURLRequest adjustTimeoutSeconds for request: " << mDetail->mURL << llendl;
+		if (mState == STATE_INITIALIZED)
+		{
+			llinfos << "LLURLRequest adjustTimeoutSeconds called during upload" << llendl;
+		}
 	}
 
 	switch(mState)
diff --git a/indra/llmessage/tests/llhttpclient_test.cpp b/indra/llmessage/tests/llhttpclient_test.cpp
index 87cbafa404c441e83a481e0302fbfe021c7096bf..559001d0797a351ef9bcd9a1b3946ec516ce45f3 100755
--- a/indra/llmessage/tests/llhttpclient_test.cpp
+++ b/indra/llmessage/tests/llhttpclient_test.cpp
@@ -241,7 +241,7 @@ namespace tut
 		ensureStatusOK();
 		ensure_equals("echoed result matches", getResult(), sd);
 	}
-		
+
 	template<> template<>
 		void HTTPClientTestObject::test<4>()
 	{
diff --git a/indra/llprimitive/CMakeLists.txt b/indra/llprimitive/CMakeLists.txt
index 1768a06a279f316eb66ae62ecd0db086fd105ca9..0dd13916bf5e8eb532776597a3e524b82b0e464d 100755
--- a/indra/llprimitive/CMakeLists.txt
+++ b/indra/llprimitive/CMakeLists.txt
@@ -24,6 +24,8 @@ include_directories(SYSTEM
     )
 
 set(llprimitive_SOURCE_FILES
+    llmaterialid.cpp
+    llmaterial.cpp
     llmaterialtable.cpp
     llmediaentry.cpp
     llmodel.cpp
@@ -41,6 +43,8 @@ set(llprimitive_HEADER_FILES
     CMakeLists.txt
 
     legacy_object_types.h
+    llmaterial.h
+    llmaterialid.h
     llmaterialtable.h
     llmediaentry.h
     llmodel.h
diff --git a/indra/llprimitive/llmaterial.cpp b/indra/llprimitive/llmaterial.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..cf4c645cfdf509d36951bad4a62e28dc3fd40e61
--- /dev/null
+++ b/indra/llprimitive/llmaterial.cpp
@@ -0,0 +1,227 @@
+/**
+ * @file llmaterial.cpp
+ * @brief Material definition
+ *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+
+#include "llmaterial.h"
+
+/**
+ * Materials cap parameters
+ */
+#define MATERIALS_CAP_NORMAL_MAP_FIELD            "NormMap"
+#define MATERIALS_CAP_NORMAL_MAP_OFFSET_X_FIELD   "NormOffsetX"
+#define MATERIALS_CAP_NORMAL_MAP_OFFSET_Y_FIELD   "NormOffsetY"
+#define MATERIALS_CAP_NORMAL_MAP_REPEAT_X_FIELD   "NormRepeatX"
+#define MATERIALS_CAP_NORMAL_MAP_REPEAT_Y_FIELD   "NormRepeatY"
+#define MATERIALS_CAP_NORMAL_MAP_ROTATION_FIELD   "NormRotation"
+
+#define MATERIALS_CAP_SPECULAR_MAP_FIELD          "SpecMap"
+#define MATERIALS_CAP_SPECULAR_MAP_OFFSET_X_FIELD "SpecOffsetX"
+#define MATERIALS_CAP_SPECULAR_MAP_OFFSET_Y_FIELD "SpecOffsetY"
+#define MATERIALS_CAP_SPECULAR_MAP_REPEAT_X_FIELD "SpecRepeatX"
+#define MATERIALS_CAP_SPECULAR_MAP_REPEAT_Y_FIELD "SpecRepeatY"
+#define MATERIALS_CAP_SPECULAR_MAP_ROTATION_FIELD "SpecRotation"
+
+#define MATERIALS_CAP_SPECULAR_COLOR_FIELD        "SpecColor"
+#define MATERIALS_CAP_SPECULAR_EXP_FIELD          "SpecExp"
+#define MATERIALS_CAP_ENV_INTENSITY_FIELD         "EnvIntensity"
+#define MATERIALS_CAP_ALPHA_MASK_CUTOFF_FIELD     "AlphaMaskCutoff"
+#define MATERIALS_CAP_DIFFUSE_ALPHA_MODE_FIELD    "DiffuseAlphaMode"
+
+const LLColor4U LLMaterial::DEFAULT_SPECULAR_LIGHT_COLOR(255,255,255,255);
+
+/**
+ * Materials constants
+ */
+
+const F32 MATERIALS_MULTIPLIER                   = 10000.f;
+
+/**
+ * Helper functions
+ */
+
+template<typename T> T getMaterialField(const LLSD& data, const std::string& field, const LLSD::Type field_type)
+{
+	if ( (data.has(field)) && (field_type == data[field].type()) )
+	{
+		return (T)data[field];
+	}
+	llerrs << "Missing or mistyped field '" << field << "' in material definition" << llendl;
+	return (T)LLSD();
+}
+
+// GCC didn't like the generic form above for some reason
+template<> LLUUID getMaterialField(const LLSD& data, const std::string& field, const LLSD::Type field_type)
+{
+	if ( (data.has(field)) && (field_type == data[field].type()) )
+	{
+		return data[field].asUUID();
+	}
+	llerrs << "Missing or mistyped field '" << field << "' in material definition" << llendl;
+	return LLUUID::null;
+}
+
+/**
+ * LLMaterial class
+ */
+
+const LLMaterial LLMaterial::null;
+
+LLMaterial::LLMaterial()
+	: mNormalOffsetX(0.0f)
+	, mNormalOffsetY(0.0f)
+	, mNormalRepeatX(1.0f)
+	, mNormalRepeatY(1.0f)
+	, mNormalRotation(0.0f)
+	, mSpecularOffsetX(0.0f)
+	, mSpecularOffsetY(0.0f)
+	, mSpecularRepeatX(1.0f)
+	, mSpecularRepeatY(1.0f)
+	, mSpecularRotation(0.0f)
+	, mSpecularLightColor(LLMaterial::DEFAULT_SPECULAR_LIGHT_COLOR)
+	, mSpecularLightExponent(LLMaterial::DEFAULT_SPECULAR_LIGHT_EXPONENT)
+	, mEnvironmentIntensity(LLMaterial::DEFAULT_ENV_INTENSITY)
+	, mDiffuseAlphaMode(LLMaterial::DIFFUSE_ALPHA_MODE_BLEND)
+	, mAlphaMaskCutoff(0)
+{
+}
+
+LLMaterial::LLMaterial(const LLSD& material_data)
+{
+	fromLLSD(material_data);
+}
+
+LLSD LLMaterial::asLLSD() const
+{
+	LLSD material_data;
+
+	material_data[MATERIALS_CAP_NORMAL_MAP_FIELD] = mNormalID;
+	material_data[MATERIALS_CAP_NORMAL_MAP_OFFSET_X_FIELD] = llround(mNormalOffsetX * MATERIALS_MULTIPLIER);
+	material_data[MATERIALS_CAP_NORMAL_MAP_OFFSET_Y_FIELD] = llround(mNormalOffsetY * MATERIALS_MULTIPLIER);
+	material_data[MATERIALS_CAP_NORMAL_MAP_REPEAT_X_FIELD] = llround(mNormalRepeatX * MATERIALS_MULTIPLIER);
+	material_data[MATERIALS_CAP_NORMAL_MAP_REPEAT_Y_FIELD] = llround(mNormalRepeatY * MATERIALS_MULTIPLIER);
+	material_data[MATERIALS_CAP_NORMAL_MAP_ROTATION_FIELD] = llround(mNormalRotation * MATERIALS_MULTIPLIER);
+
+	material_data[MATERIALS_CAP_SPECULAR_MAP_FIELD] = mSpecularID;
+	material_data[MATERIALS_CAP_SPECULAR_MAP_OFFSET_X_FIELD] = llround(mSpecularOffsetX * MATERIALS_MULTIPLIER);
+	material_data[MATERIALS_CAP_SPECULAR_MAP_OFFSET_Y_FIELD] = llround(mSpecularOffsetY * MATERIALS_MULTIPLIER);
+	material_data[MATERIALS_CAP_SPECULAR_MAP_REPEAT_X_FIELD] = llround(mSpecularRepeatX * MATERIALS_MULTIPLIER);
+	material_data[MATERIALS_CAP_SPECULAR_MAP_REPEAT_Y_FIELD] = llround(mSpecularRepeatY * MATERIALS_MULTIPLIER);
+	material_data[MATERIALS_CAP_SPECULAR_MAP_ROTATION_FIELD] = llround(mSpecularRotation * MATERIALS_MULTIPLIER);
+
+	material_data[MATERIALS_CAP_SPECULAR_COLOR_FIELD]     = mSpecularLightColor.getValue();
+	material_data[MATERIALS_CAP_SPECULAR_EXP_FIELD]       = mSpecularLightExponent;
+	material_data[MATERIALS_CAP_ENV_INTENSITY_FIELD]      = mEnvironmentIntensity;
+	material_data[MATERIALS_CAP_DIFFUSE_ALPHA_MODE_FIELD] = mDiffuseAlphaMode;
+	material_data[MATERIALS_CAP_ALPHA_MASK_CUTOFF_FIELD]  = mAlphaMaskCutoff;
+
+	return material_data;
+}
+
+void LLMaterial::fromLLSD(const LLSD& material_data)
+{
+	mNormalID = getMaterialField<LLSD::UUID>(material_data, MATERIALS_CAP_NORMAL_MAP_FIELD, LLSD::TypeUUID);
+	mNormalOffsetX  = (F32)getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_NORMAL_MAP_OFFSET_X_FIELD, LLSD::TypeInteger) / MATERIALS_MULTIPLIER;
+	mNormalOffsetY  = (F32)getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_NORMAL_MAP_OFFSET_Y_FIELD, LLSD::TypeInteger) / MATERIALS_MULTIPLIER;
+	mNormalRepeatX  = (F32)getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_NORMAL_MAP_REPEAT_X_FIELD, LLSD::TypeInteger) / MATERIALS_MULTIPLIER;
+	mNormalRepeatY  = (F32)getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_NORMAL_MAP_REPEAT_Y_FIELD, LLSD::TypeInteger) / MATERIALS_MULTIPLIER;
+	mNormalRotation = (F32)getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_NORMAL_MAP_ROTATION_FIELD, LLSD::TypeInteger) / MATERIALS_MULTIPLIER;
+
+	mSpecularID = getMaterialField<LLSD::UUID>(material_data, MATERIALS_CAP_SPECULAR_MAP_FIELD, LLSD::TypeUUID);
+	mSpecularOffsetX  = (F32)getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_SPECULAR_MAP_OFFSET_X_FIELD, LLSD::TypeInteger) / MATERIALS_MULTIPLIER;
+	mSpecularOffsetY  = (F32)getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_SPECULAR_MAP_OFFSET_Y_FIELD, LLSD::TypeInteger) / MATERIALS_MULTIPLIER;
+	mSpecularRepeatX  = (F32)getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_SPECULAR_MAP_REPEAT_X_FIELD, LLSD::TypeInteger) / MATERIALS_MULTIPLIER;
+	mSpecularRepeatY  = (F32)getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_SPECULAR_MAP_REPEAT_Y_FIELD, LLSD::TypeInteger) / MATERIALS_MULTIPLIER;
+	mSpecularRotation = (F32)getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_SPECULAR_MAP_ROTATION_FIELD, LLSD::TypeInteger) / MATERIALS_MULTIPLIER;
+
+	mSpecularLightColor.setValue(getMaterialField<LLSD>(material_data, MATERIALS_CAP_SPECULAR_COLOR_FIELD, LLSD::TypeArray));
+	mSpecularLightExponent = (U8)getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_SPECULAR_EXP_FIELD,       LLSD::TypeInteger);
+	mEnvironmentIntensity  = (U8)getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_ENV_INTENSITY_FIELD,      LLSD::TypeInteger);
+	mDiffuseAlphaMode      = (U8)getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_DIFFUSE_ALPHA_MODE_FIELD, LLSD::TypeInteger);
+	mAlphaMaskCutoff       = (U8)getMaterialField<LLSD::Integer>(material_data, MATERIALS_CAP_ALPHA_MASK_CUTOFF_FIELD,  LLSD::TypeInteger);
+}
+
+bool LLMaterial::isNull() const
+{
+	return (*this == null);
+}
+
+bool LLMaterial::operator == (const LLMaterial& rhs) const
+{
+	return 
+		(mNormalID == rhs.mNormalID) && (mNormalOffsetX == rhs.mNormalOffsetX) && (mNormalOffsetY == rhs.mNormalOffsetY) &&
+		(mNormalRepeatX == rhs.mNormalRepeatX) && (mNormalRepeatY == rhs.mNormalRepeatY) && (mNormalRotation == rhs.mNormalRotation) &&
+		(mSpecularID == rhs.mSpecularID) && (mSpecularOffsetX == rhs.mSpecularOffsetX) && (mSpecularOffsetY == rhs.mSpecularOffsetY) &&
+		(mSpecularRepeatX == rhs.mSpecularRepeatX) && (mSpecularRepeatY == rhs.mSpecularRepeatY) && (mSpecularRotation == rhs.mSpecularRotation) &&
+		(mSpecularLightColor == rhs.mSpecularLightColor) && (mSpecularLightExponent == rhs.mSpecularLightExponent) &&
+		(mEnvironmentIntensity == rhs.mEnvironmentIntensity) && (mDiffuseAlphaMode == rhs.mDiffuseAlphaMode) && (mAlphaMaskCutoff == rhs.mAlphaMaskCutoff);
+}
+
+bool LLMaterial::operator != (const LLMaterial& rhs) const
+{
+	return !(*this == rhs);
+}
+
+
+U32 LLMaterial::getShaderMask(U32 alpha_mode)
+{ //NEVER incorporate this value into the message system -- this function will vary depending on viewer implementation
+	U32 ret = 0;
+
+	//two least significant bits are "diffuse alpha mode"
+	if (alpha_mode != DIFFUSE_ALPHA_MODE_DEFAULT)
+	{
+		ret = alpha_mode;
+	}
+	else
+	{
+		ret = getDiffuseAlphaMode();
+	}
+
+	llassert(ret < SHADER_COUNT);
+
+	//next bit is whether or not specular map is present
+	const U32 SPEC_BIT = 0x4;
+
+	if (getSpecularID().notNull())
+	{
+		ret |= SPEC_BIT;
+	}
+
+	llassert(ret < SHADER_COUNT);
+	
+	//next bit is whether or not normal map is present
+	const U32 NORM_BIT = 0x8;
+	if (getNormalID().notNull())
+	{
+		ret |= NORM_BIT;
+	}
+
+	llassert(ret < SHADER_COUNT);
+
+	return ret;
+}
+
+
diff --git a/indra/llprimitive/llmaterial.h b/indra/llprimitive/llmaterial.h
new file mode 100644
index 0000000000000000000000000000000000000000..9f52a3f6c1b1c2c32c759a770a2fc2b0ae6b6534
--- /dev/null
+++ b/indra/llprimitive/llmaterial.h
@@ -0,0 +1,155 @@
+/**
+ * @file llmaterial.h
+ * @brief Material definition
+ *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLMATERIAL_H
+#define LL_LLMATERIAL_H
+
+#include <boost/shared_ptr.hpp>
+
+#include "llmaterialid.h"
+#include "llsd.h"
+#include "v4coloru.h"
+#include "llpointer.h"
+#include "llrefcount.h"
+
+class LLMaterial : public LLRefCount
+{
+public:
+
+	typedef enum
+	{
+		DIFFUSE_ALPHA_MODE_NONE = 0,
+		DIFFUSE_ALPHA_MODE_BLEND = 1,
+		DIFFUSE_ALPHA_MODE_MASK = 2,
+		DIFFUSE_ALPHA_MODE_EMISSIVE = 3,
+		DIFFUSE_ALPHA_MODE_DEFAULT = 4,
+	} eDiffuseAlphaMode;
+
+	typedef enum
+	{
+		SHADER_COUNT = 16,
+		ALPHA_SHADER_COUNT = 4
+	} eShaderCount;
+
+	
+	
+	static const U8			DEFAULT_SPECULAR_LIGHT_EXPONENT = ((U8)(0.2f * 255));
+	static const LLColor4U	DEFAULT_SPECULAR_LIGHT_COLOR;
+	static const U8			DEFAULT_ENV_INTENSITY = 0;
+
+	LLMaterial();
+	LLMaterial(const LLSD& material_data);
+
+	LLSD asLLSD() const;
+	void fromLLSD(const LLSD& material_data);
+
+	const LLUUID& getNormalID() const { return mNormalID; }
+	void		setNormalID(const LLUUID& normal_id) { mNormalID = normal_id; }
+	void		getNormalOffset(F32& offset_x, F32& offset_y) const { offset_x = mNormalOffsetX; offset_y = mNormalOffsetY; }
+	F32		getNormalOffsetX() const { return mNormalOffsetX; }
+	F32		getNormalOffsetY() const { return mNormalOffsetY; }
+
+	void		setNormalOffset(F32 offset_x, F32 offset_y) { mNormalOffsetX = offset_x; mNormalOffsetY = offset_y; }
+	void		setNormalOffsetX(F32 offset_x) { mNormalOffsetX = offset_x; }
+	void		setNormalOffsetY(F32 offset_y) { mNormalOffsetY = offset_y; }
+
+	void		getNormalRepeat(F32& repeat_x, F32& repeat_y) const { repeat_x = mNormalRepeatX; repeat_y = mNormalRepeatY; }
+	F32		getNormalRepeatX() const { return mNormalRepeatX; }
+	F32		getNormalRepeatY() const { return mNormalRepeatY; }
+
+	void		setNormalRepeat(F32 repeat_x, F32 repeat_y) { mNormalRepeatX = repeat_x; mNormalRepeatY = repeat_y; }
+	void		setNormalRepeatX(F32 repeat_x) { mNormalRepeatX = repeat_x; }
+	void		setNormalRepeatY(F32 repeat_y) { mNormalRepeatY = repeat_y; }
+
+	F32		getNormalRotation() const { return mNormalRotation; }
+	void		setNormalRotation(F32 rot) { mNormalRotation = rot; }
+
+	const LLUUID& getSpecularID() const { return mSpecularID; }
+	void		setSpecularID(const LLUUID& specular_id)  { mSpecularID = specular_id; }
+	void		getSpecularOffset(F32& offset_x, F32& offset_y) const { offset_x = mSpecularOffsetX; offset_y = mSpecularOffsetY; }
+	F32		getSpecularOffsetX() const { return mSpecularOffsetX; }
+	F32		getSpecularOffsetY() const { return mSpecularOffsetY; }
+
+	void		setSpecularOffset(F32 offset_x, F32 offset_y) { mSpecularOffsetX = offset_x; mSpecularOffsetY = offset_y; }
+	void		setSpecularOffsetX(F32 offset_x) { mSpecularOffsetX = offset_x; }
+	void		setSpecularOffsetY(F32 offset_y) { mSpecularOffsetY = offset_y; }
+
+	void		getSpecularRepeat(F32& repeat_x, F32& repeat_y) const { repeat_x = mSpecularRepeatX; repeat_y = mSpecularRepeatY; }
+	F32		getSpecularRepeatX() const { return mSpecularRepeatX; }
+	F32		getSpecularRepeatY() const { return mSpecularRepeatY; }
+
+	void		setSpecularRepeat(F32 repeat_x, F32 repeat_y) { mSpecularRepeatX = repeat_x; mSpecularRepeatY = repeat_y; }
+	void		setSpecularRepeatX(F32 repeat_x) { mSpecularRepeatX = repeat_x; }
+	void		setSpecularRepeatY(F32 repeat_y) { mSpecularRepeatY = repeat_y; }
+
+	F32		getSpecularRotation() const { return mSpecularRotation; }
+	void		setSpecularRotation(F32 rot) { mSpecularRotation = rot; }
+
+	const LLColor4U getSpecularLightColor() const { return mSpecularLightColor; }
+	void		setSpecularLightColor(const LLColor4U& color) { mSpecularLightColor = color; }
+	U8			getSpecularLightExponent() const { return mSpecularLightExponent; }
+	void		setSpecularLightExponent(U8 exponent) { mSpecularLightExponent = exponent; }
+	U8			getEnvironmentIntensity() const { return mEnvironmentIntensity; }
+	void		setEnvironmentIntensity(U8 intensity) { mEnvironmentIntensity = intensity; }
+	U8			getDiffuseAlphaMode() const { return mDiffuseAlphaMode; }
+	void		setDiffuseAlphaMode(U8 alpha_mode) { mDiffuseAlphaMode = alpha_mode; }
+	U8			getAlphaMaskCutoff() const { return mAlphaMaskCutoff; }
+	void		setAlphaMaskCutoff(U8 cutoff) { mAlphaMaskCutoff = cutoff; }
+
+	bool		isNull() const;
+	static const LLMaterial null;
+
+	bool		operator == (const LLMaterial& rhs) const;
+	bool		operator != (const LLMaterial& rhs) const;
+
+	U32			getShaderMask(U32 alpha_mode = DIFFUSE_ALPHA_MODE_DEFAULT);
+
+protected:
+	LLUUID		mNormalID;
+	F32			mNormalOffsetX;
+	F32			mNormalOffsetY;
+	F32			mNormalRepeatX;
+	F32			mNormalRepeatY;
+	F32			mNormalRotation;
+
+	LLUUID		mSpecularID;
+	F32			mSpecularOffsetX;
+	F32			mSpecularOffsetY;
+	F32			mSpecularRepeatX;
+	F32			mSpecularRepeatY;
+	F32			mSpecularRotation;
+
+	LLColor4U	mSpecularLightColor;
+	U8			mSpecularLightExponent;
+	U8			mEnvironmentIntensity;
+	U8			mDiffuseAlphaMode;
+	U8			mAlphaMaskCutoff;
+};
+
+typedef LLPointer<LLMaterial> LLMaterialPtr;
+
+#endif // LL_LLMATERIAL_H
+
diff --git a/indra/llprimitive/llmaterialid.cpp b/indra/llprimitive/llmaterialid.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..820f62c43ce04941c51f5ab28b208d99f1fcdec0
--- /dev/null
+++ b/indra/llprimitive/llmaterialid.cpp
@@ -0,0 +1,183 @@
+/** 
+* @file llmaterialid.cpp
+* @brief Implementation of llmaterialid
+* @author Stinson@lindenlab.com
+*
+* $LicenseInfo:firstyear=2012&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2012, 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$
+*/
+
+#include "linden_common.h"
+
+#include "llmaterialid.h"
+
+#include <string>
+
+#include "llformat.h"
+
+const LLMaterialID LLMaterialID::null;
+
+LLMaterialID::LLMaterialID()
+{
+	clear();
+}
+
+LLMaterialID::LLMaterialID(const LLSD& pMaterialID)
+{
+	llassert(pMaterialID.isBinary());
+	parseFromBinary(pMaterialID.asBinary());
+}
+
+LLMaterialID::LLMaterialID(const LLSD::Binary& pMaterialID)
+{
+	parseFromBinary(pMaterialID);
+}
+
+LLMaterialID::LLMaterialID(const void* pMemory)
+{
+	set(pMemory);
+}
+
+LLMaterialID::LLMaterialID(const LLMaterialID& pOtherMaterialID)
+{
+	copyFromOtherMaterialID(pOtherMaterialID);
+}
+
+LLMaterialID::~LLMaterialID()
+{
+}
+
+bool LLMaterialID::operator == (const LLMaterialID& pOtherMaterialID) const
+{
+	return (compareToOtherMaterialID(pOtherMaterialID) == 0);
+}
+
+bool LLMaterialID::operator != (const LLMaterialID& pOtherMaterialID) const
+{
+	return (compareToOtherMaterialID(pOtherMaterialID) != 0);
+}
+
+bool LLMaterialID::operator < (const LLMaterialID& pOtherMaterialID) const
+{
+	return (compareToOtherMaterialID(pOtherMaterialID) < 0);
+}
+
+bool LLMaterialID::operator <= (const LLMaterialID& pOtherMaterialID) const
+{
+	return (compareToOtherMaterialID(pOtherMaterialID) <= 0);
+}
+
+bool LLMaterialID::operator > (const LLMaterialID& pOtherMaterialID) const
+{
+	return (compareToOtherMaterialID(pOtherMaterialID) > 0);
+}
+
+bool LLMaterialID::operator >= (const LLMaterialID& pOtherMaterialID) const
+{
+	return (compareToOtherMaterialID(pOtherMaterialID) >= 0);
+}
+
+LLMaterialID& LLMaterialID::operator = (const LLMaterialID& pOtherMaterialID)
+{
+	copyFromOtherMaterialID(pOtherMaterialID);
+	return (*this);
+}
+
+bool LLMaterialID::isNull() const
+{
+	return (compareToOtherMaterialID(LLMaterialID::null) == 0);
+}
+
+const U8* LLMaterialID::get() const
+{
+	return mID;
+}
+
+void LLMaterialID::set(const void* pMemory)
+{
+	llassert(pMemory != NULL);
+
+	// assumes that the required size of memory is available
+	memcpy(mID, pMemory, MATERIAL_ID_SIZE * sizeof(U8));
+}
+
+void LLMaterialID::clear()
+{
+	memset(mID, 0, MATERIAL_ID_SIZE * sizeof(U8));
+}
+
+LLSD LLMaterialID::asLLSD() const
+{
+	LLSD::Binary materialIDBinary;
+
+	materialIDBinary.resize(MATERIAL_ID_SIZE * sizeof(U8));
+	memcpy(materialIDBinary.data(), mID, MATERIAL_ID_SIZE * sizeof(U8));
+
+	LLSD materialID = materialIDBinary;
+	return materialID;
+}
+
+std::string LLMaterialID::asString() const
+{
+	std::string materialIDString;
+	for (unsigned int i = 0U; i < static_cast<unsigned int>(MATERIAL_ID_SIZE / sizeof(U32)); ++i)
+	{
+		if (i != 0U)
+		{
+			materialIDString += "-";
+		}
+		const U32 *value = reinterpret_cast<const U32*>(&get()[i * sizeof(U32)]);
+		materialIDString += llformat("%08x", *value);
+	}
+	return materialIDString;
+}
+
+std::ostream& operator<<(std::ostream& s, const LLMaterialID &material_id)
+{
+	s << material_id.asString();
+	return s;
+}
+
+
+void LLMaterialID::parseFromBinary (const LLSD::Binary& pMaterialID)
+{
+	llassert(pMaterialID.size() == (MATERIAL_ID_SIZE * sizeof(U8)));
+	memcpy(mID, &pMaterialID[0], MATERIAL_ID_SIZE * sizeof(U8));
+}
+
+void LLMaterialID::copyFromOtherMaterialID(const LLMaterialID& pOtherMaterialID)
+{
+	memcpy(mID, pOtherMaterialID.get(), MATERIAL_ID_SIZE * sizeof(U8));
+}
+
+int LLMaterialID::compareToOtherMaterialID(const LLMaterialID& pOtherMaterialID) const
+{
+	int retVal = 0;
+
+	for (unsigned int i = 0U; (retVal == 0) && (i < static_cast<unsigned int>(MATERIAL_ID_SIZE / sizeof(U32))); ++i)
+	{
+		const U32 *thisValue = reinterpret_cast<const U32*>(&get()[i * sizeof(U32)]);
+		const U32 *otherValue = reinterpret_cast<const U32*>(&pOtherMaterialID.get()[i * sizeof(U32)]);
+		retVal = ((*thisValue < *otherValue) ? -1 : ((*thisValue > *otherValue) ? 1 : 0));
+	}
+
+	return retVal;
+}
diff --git a/indra/llprimitive/llmaterialid.h b/indra/llprimitive/llmaterialid.h
new file mode 100644
index 0000000000000000000000000000000000000000..0a952040859625b2846e846001ea4be699a44093
--- /dev/null
+++ b/indra/llprimitive/llmaterialid.h
@@ -0,0 +1,76 @@
+/** 
+* @file   llmaterialid.h
+* @brief  Header file for llmaterialid
+* @author Stinson@lindenlab.com
+*
+* $LicenseInfo:firstyear=2012&license=viewerlgpl$
+* Second Life Viewer Source Code
+* Copyright (C) 2012, Linden Research, Inc.
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU Lesser General Public
+* License as published by the Free Software Foundation;
+* version 2.1 of the License only.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this library; if not, write to the Free Software
+* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+*
+* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+* $/LicenseInfo$
+*/
+#ifndef LL_LLMATERIALID_H
+#define LL_LLMATERIALID_H
+
+#define MATERIAL_ID_SIZE 16
+
+#include <string>
+
+class LLMaterialID
+{
+public:
+	LLMaterialID();
+	LLMaterialID(const LLSD& pMaterialID);
+	LLMaterialID(const LLSD::Binary& pMaterialID);
+	LLMaterialID(const void* pMemory);
+	LLMaterialID(const LLMaterialID& pOtherMaterialID);
+	~LLMaterialID();
+
+	bool          operator == (const LLMaterialID& pOtherMaterialID) const;
+	bool          operator != (const LLMaterialID& pOtherMaterialID) const;
+
+	bool          operator < (const LLMaterialID& pOtherMaterialID) const;
+	bool          operator <= (const LLMaterialID& pOtherMaterialID) const;
+	bool          operator > (const LLMaterialID& pOtherMaterialID) const;
+	bool          operator >= (const LLMaterialID& pOtherMaterialID) const;
+
+	LLMaterialID& operator = (const LLMaterialID& pOtherMaterialID);
+
+	bool          isNull() const;
+
+	const U8*     get() const;
+	void          set(const void* pMemory);
+	void          clear();
+
+	LLSD          asLLSD() const;
+	std::string   asString() const;
+
+	friend std::ostream& operator<<(std::ostream& s, const LLMaterialID &material_id);
+
+	static const LLMaterialID null;
+
+private:
+	void parseFromBinary(const LLSD::Binary& pMaterialID);
+	void copyFromOtherMaterialID(const LLMaterialID& pOtherMaterialID);
+	int  compareToOtherMaterialID(const LLMaterialID& pOtherMaterialID) const;
+
+	U8 mID[MATERIAL_ID_SIZE];
+} ;
+
+#endif // LL_LLMATERIALID_H
+
diff --git a/indra/llprimitive/llprimitive.cpp b/indra/llprimitive/llprimitive.cpp
index c340fc2d353af999925b9768faa888341b83bb03..2fa77177f58e704f4c7e3eece97e42e90a432041 100755
--- a/indra/llprimitive/llprimitive.cpp
+++ b/indra/llprimitive/llprimitive.cpp
@@ -39,6 +39,7 @@
 #include "llsdutil_math.h"
 #include "llprimtexturelist.h"
 #include "imageids.h"
+#include "llmaterialid.h"
 
 /**
  * exported constants
@@ -314,6 +315,15 @@ S32  LLPrimitive::setTERotation(const U8 index, const F32 r)
 	return mTextureList.setRotation(index, r);
 }
 
+S32 LLPrimitive::setTEMaterialID(const U8 index, const LLMaterialID& pMaterialID)
+{
+	return mTextureList.setMaterialID(index, pMaterialID);
+}
+
+S32 LLPrimitive::setTEMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams)
+{
+	return mTextureList.setMaterialParams(index, pMaterialParams);
+}
 
 //===============================================================
 S32  LLPrimitive::setTEBumpShinyFullbright(const U8 index, const U8 bump)
@@ -364,6 +374,23 @@ S32 LLPrimitive::setTEGlow(const U8 index, const F32 glow)
 	return mTextureList.setGlow(index, glow);
 }
 
+void LLPrimitive::setAllTESelected(bool sel)
+{
+	for (int i = 0, cnt = getNumTEs(); i < cnt; i++)
+	{
+		setTESelected(i, sel);
+	}
+}
+	
+void LLPrimitive::setTESelected(const U8 te, bool sel)
+{
+	LLTextureEntry* tep = getTE(te);
+	if ( (tep) && (tep->setSelected(sel)) && (!sel) && (tep->hasPendingMaterialUpdate()) )
+	{
+		LLMaterialID material_id = tep->getMaterialID();
+		setTEMaterialID(te, material_id);
+	}
+}
 
 LLPCode LLPrimitive::legacyToPCode(const U8 legacy)
 {
@@ -1044,7 +1071,7 @@ S32 LLPrimitive::unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 dat
 	
 	while ((cur_ptr < buffer_end) && (*cur_ptr != 0))
 	{
-//		llinfos << "TE exception" << llendl;
+		LL_DEBUGS("TEFieldDecode") << "TE exception" << LL_ENDL;
 		i = 0;
 		while (*cur_ptr & 0x80)
 		{
@@ -1059,14 +1086,16 @@ S32 LLPrimitive::unpackTEField(U8 *cur_ptr, U8 *buffer_end, U8 *data_ptr, U8 dat
 			if (i & 0x01)
 			{
 				htonmemcpy(data_ptr+(j*data_size),cur_ptr,type,data_size);
-//				char foo[64];
-//				sprintf(foo,"%x %x",*(data_ptr+(j*data_size)), *(data_ptr+(j*data_size)+1));
-//				llinfos << "Assigning " << foo << " to face " << j << llendl;			
+				LL_DEBUGS("TEFieldDecode") << "Assigning " ;
+				char foo[64];
+				sprintf(foo,"%x %x",*(data_ptr+(j*data_size)), *(data_ptr+(j*data_size)+1));
+				LL_CONT << foo << " to face " << j << LL_ENDL;
 			}
 			i = i >> 1;
 		}
 		cur_ptr += data_size;		
 	}
+	llassert(cur_ptr <= buffer_end); // buffer underrun
 	return (S32)(cur_ptr - start_loc);
 }
 
@@ -1088,6 +1117,7 @@ BOOL LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const
 	U8	   bump[MAX_TES];
 	U8	   media_flags[MAX_TES];
     U8     glow[MAX_TES];
+	U8     material_data[MAX_TES*16];
 	
 	const U32 MAX_TE_BUFFER = 4096;
 	U8 packed_buffer[MAX_TE_BUFFER];
@@ -1125,6 +1155,9 @@ BOOL LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const
 			bump[face_index] = te->getBumpShinyFullbright();
 			media_flags[face_index] = te->getMediaTexGen();
 			glow[face_index] = (U8) llround((llclamp(te->getGlow(), 0.0f, 1.0f) * (F32)0xFF));
+
+			// Directly sending material_ids is not safe!
+			memcpy(&material_data[face_index*16],getTE(face_index)->getMaterialID().get(),16);	/* Flawfinder: ignore */ 
 		}
 
 		cur_ptr += packTEField(cur_ptr, (U8 *)image_ids, sizeof(LLUUID),last_face_index, MVT_LLUUID);
@@ -1146,6 +1179,8 @@ BOOL LLPrimitive::packTEMessage(LLMessageSystem *mesgsys) const
 		cur_ptr += packTEField(cur_ptr, (U8 *)media_flags, 1 ,last_face_index, MVT_U8);
 		*cur_ptr++ = 0;
 		cur_ptr += packTEField(cur_ptr, (U8 *)glow, 1 ,last_face_index, MVT_U8);
+		*cur_ptr++ = 0;
+		cur_ptr += packTEField(cur_ptr, (U8 *)material_data, 16, last_face_index, MVT_LLUUID);
 	}
    	mesgsys->addBinaryDataFast(_PREHASH_TextureEntry, packed_buffer, (S32)(cur_ptr - packed_buffer));
 
@@ -1167,6 +1202,7 @@ BOOL LLPrimitive::packTEMessage(LLDataPacker &dp) const
 	U8	   bump[MAX_TES];
 	U8	   media_flags[MAX_TES];
     U8     glow[MAX_TES];
+	U8     material_data[MAX_TES*16];
 	
 	const U32 MAX_TE_BUFFER = 4096;
 	U8 packed_buffer[MAX_TE_BUFFER];
@@ -1204,6 +1240,9 @@ BOOL LLPrimitive::packTEMessage(LLDataPacker &dp) const
 			bump[face_index] = te->getBumpShinyFullbright();
 			media_flags[face_index] = te->getMediaTexGen();
             glow[face_index] = (U8) llround((llclamp(te->getGlow(), 0.0f, 1.0f) * (F32)0xFF));
+
+			// Directly sending material_ids is not safe!
+			memcpy(&material_data[face_index*16],getTE(face_index)->getMaterialID().get(),16);	/* Flawfinder: ignore */ 
 		}
 
 		cur_ptr += packTEField(cur_ptr, (U8 *)image_ids, sizeof(LLUUID),last_face_index, MVT_LLUUID);
@@ -1225,6 +1264,8 @@ BOOL LLPrimitive::packTEMessage(LLDataPacker &dp) const
 		cur_ptr += packTEField(cur_ptr, (U8 *)media_flags, 1 ,last_face_index, MVT_U8);
 		*cur_ptr++ = 0;
 		cur_ptr += packTEField(cur_ptr, (U8 *)glow, 1 ,last_face_index, MVT_U8);
+		*cur_ptr++ = 0;
+		cur_ptr += packTEField(cur_ptr, (U8 *)material_data, 16, last_face_index, MVT_LLUUID);
 	}
 
 	dp.packBinaryData(packed_buffer, (S32)(cur_ptr - packed_buffer), "TextureEntry");
@@ -1234,6 +1275,9 @@ BOOL LLPrimitive::packTEMessage(LLDataPacker &dp) const
 S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name, const S32 block_num, LLTEContents& tec)
 {
 	S32 retval = 0;
+   // temp buffer for material ID processing
+   // data will end up in tec.material_id[]	
+   U8 material_data[LLTEContents::MAX_TES*16];
 
 	if (block_num < 0)
 	{
@@ -1282,14 +1326,29 @@ S32 LLPrimitive::parseTEMessage(LLMessageSystem* mesgsys, char const* block_name
 	cur_ptr++;
 	cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)tec.glow, 1, tec.face_count, MVT_U8);
 
+	if (cur_ptr < tec.packed_buffer + tec.size)
+	{
+		cur_ptr++;
+		cur_ptr += unpackTEField(cur_ptr, tec.packed_buffer+tec.size, (U8 *)material_data, 16, tec.face_count, MVT_LLUUID);
+	}
+	else
+	{
+		memset(material_data, 0, sizeof(material_data));
+	}
+	
+	for (U32 i = 0; i < tec.face_count; i++)
+	{
+		tec.material_ids[i].set(&material_data[i * 16]);
+	}
+	
 	retval = 1;
 	return retval;
-}
-
+	}
+	
 S32 LLPrimitive::applyParsedTEMessage(LLTEContents& tec)
 {
 	S32 retval = 0;
-
+	
 	LLColor4 color;
 	LLColor4U coloru;
 	for (U32 i = 0; i < tec.face_count; i++)
@@ -1302,6 +1361,9 @@ S32 LLPrimitive::applyParsedTEMessage(LLTEContents& tec)
 		retval |= setTEBumpShinyFullbright(i, tec.bump[i]);
 		retval |= setTEMediaTexGen(i, tec.media_flags[i]);
 		retval |= setTEGlow(i, (F32)tec.glow[i] / (F32)0xFF);
+		
+                retval |= setTEMaterialID(i, tec.material_ids[i]);
+		
 		coloru = LLColor4U(tec.colors + 4*i);
 
 		// Note:  This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f)
@@ -1336,6 +1398,7 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
 
 	// Avoid construction of 32 UUIDs per call
 	static LLUUID image_ids[MAX_TES];
+	static LLMaterialID material_ids[MAX_TES];
 
 	U8     image_data[MAX_TES*16];
 	U8	   colors[MAX_TES*4];
@@ -1347,6 +1410,7 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
 	U8	   bump[MAX_TES];
 	U8	   media_flags[MAX_TES];
     U8     glow[MAX_TES];
+	U8     material_data[MAX_TES*16];
 
 	const U32 MAX_TE_BUFFER = 4096;
 	U8 packed_buffer[MAX_TE_BUFFER];
@@ -1389,10 +1453,20 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
 	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)media_flags, 1, face_count, MVT_U8);
 	cur_ptr++;
 	cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)glow, 1, face_count, MVT_U8);
+	if (cur_ptr < packed_buffer + size)
+	{
+		cur_ptr++;
+		cur_ptr += unpackTEField(cur_ptr, packed_buffer+size, (U8 *)material_data, 16, face_count, MVT_LLUUID);
+	}
+	else
+	{
+		memset(material_data, 0, sizeof(material_data));
+	}
 
 	for (i = 0; i < face_count; i++)
 	{
 		memcpy(image_ids[i].mData,&image_data[i*16],16);	/* Flawfinder: ignore */ 	
+		material_ids[i].set(&material_data[i * 16]);
 	}
 	
 	LLColor4 color;
@@ -1406,6 +1480,7 @@ S32 LLPrimitive::unpackTEMessage(LLDataPacker &dp)
 		retval |= setTEBumpShinyFullbright(i, bump[i]);
 		retval |= setTEMediaTexGen(i, media_flags[i]);
 		retval |= setTEGlow(i, (F32)glow[i] / (F32)0xFF);
+		retval |= setTEMaterialID(i, material_ids[i]);
 		coloru = LLColor4U(colors + 4*i);
 
 		// Note:  This is an optimization to send common colors (1.f, 1.f, 1.f, 1.f)
diff --git a/indra/llprimitive/llprimitive.h b/indra/llprimitive/llprimitive.h
index 6a8b59c81cce09cd03587168227b60d950f07011..47a21beaaf8fbb0574e86192e84ac7dc8def6599 100755
--- a/indra/llprimitive/llprimitive.h
+++ b/indra/llprimitive/llprimitive.h
@@ -42,6 +42,7 @@ class LLMessageSystem;
 class LLVolumeParams;
 class LLColor4;
 class LLColor3;
+class LLMaterialID;
 class LLTextureEntry;
 class LLDataPacker;
 class LLVolumeMgr;
@@ -309,7 +310,8 @@ struct LLTEContents
 	U8	   bump[MAX_TES];
 	U8	   media_flags[MAX_TES];
     U8     glow[MAX_TES];
-	
+	LLMaterialID material_ids[MAX_TES];
+
 	static const U32 MAX_TE_BUFFER = 4096;
 	U8 packed_buffer[MAX_TE_BUFFER];
 
@@ -359,6 +361,7 @@ class LLPrimitive : public LLXform
 	LLTextureEntry* getTE(const U8 te_num) const;
 
 	virtual void setNumTEs(const U8 num_tes);
+	virtual void setAllTESelected(bool sel);
 	virtual void setAllTETextures(const LLUUID &tex_id);
 	virtual void setTE(const U8 index, const LLTextureEntry& te);
 	virtual S32 setTEColor(const U8 te, const LLColor4 &color);
@@ -381,7 +384,10 @@ class LLPrimitive : public LLXform
 	virtual S32 setTEFullbright(const U8 te, const U8 fullbright);
 	virtual S32 setTEMediaFlags(const U8 te, const U8 flags);
 	virtual S32 setTEGlow(const U8 te, const F32 glow);
+	virtual S32 setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID);
+	virtual S32 setTEMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams);
 	virtual BOOL setMaterial(const U8 material); // returns TRUE if material changed
+	virtual void setTESelected(const U8 te, bool sel);
 
 	void copyTEs(const LLPrimitive *primitive);
 	S32 packTEField(U8 *cur_ptr, U8 *data_ptr, U8 data_size, U8 last_face_index, EMsgVariableType type) const;
diff --git a/indra/llprimitive/llprimtexturelist.cpp b/indra/llprimitive/llprimtexturelist.cpp
index 7ef87ed382059ae529eab2fb220fbe11235a1065..537e7a6695536ed9bf0d1aa4fed2c0580210523a 100755
--- a/indra/llprimitive/llprimtexturelist.cpp
+++ b/indra/llprimitive/llprimtexturelist.cpp
@@ -27,6 +27,7 @@
 #include "linden_common.h"
 
 #include "llprimtexturelist.h"
+#include "llmaterialid.h"
 #include "lltextureentry.h"
 
 // static 
@@ -358,6 +359,24 @@ S32 LLPrimTextureList::setGlow(const U8 index, const F32 glow)
 	return TEM_CHANGE_NONE;
 }
 
+S32 LLPrimTextureList::setMaterialID(const U8 index, const LLMaterialID& pMaterialID)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setMaterialID(pMaterialID);
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLPrimTextureList::setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams)
+{
+	if (index < mEntryList.size())
+	{
+		return mEntryList[index]->setMaterialParams(pMaterialParams);
+	}
+	return TEM_CHANGE_NONE;
+}
+
 S32 LLPrimTextureList::size() const
 {
 	return mEntryList.size();
diff --git a/indra/llprimitive/llprimtexturelist.h b/indra/llprimitive/llprimtexturelist.h
index 3cfa52f1d5ef16569c28a52d08f6513d2b0f3bd1..d7fabbbb79a9f4fc080af18240f2830bfde35d98 100755
--- a/indra/llprimitive/llprimtexturelist.h
+++ b/indra/llprimitive/llprimtexturelist.h
@@ -31,9 +31,11 @@
 #include "lluuid.h"
 #include "v3color.h"
 #include "v4color.h"
+#include "llmaterial.h"
 
 
 class LLTextureEntry;
+class LLMaterialID;
 
 // this is a list of LLTextureEntry*'s because in practice the list's elements
 // are of some derived class: LLFooTextureEntry
@@ -102,6 +104,8 @@ class LLPrimTextureList
 	S32 setFullbright(const U8 index, const U8 t);
 	S32 setMediaFlags(const U8 index, const U8 media_flags);
 	S32 setGlow(const U8 index, const F32 glow);
+	S32 setMaterialID(const U8 index, const LLMaterialID& pMaterialID);
+	S32 setMaterialParams(const U8 index, const LLMaterialPtr pMaterialParams);
 
 	S32 size() const;
 
diff --git a/indra/llprimitive/lltextureentry.cpp b/indra/llprimitive/lltextureentry.cpp
index 34eff17519e60752304692a9845690ae56a48029..597f0784904f9362dcdb369d1a0e4a4ef5148299 100755
--- a/indra/llprimitive/lltextureentry.cpp
+++ b/indra/llprimitive/lltextureentry.cpp
@@ -29,6 +29,7 @@
 #include "lluuid.h"
 #include "llmediaentry.h"
 #include "lltextureentry.h"
+#include "llmaterialid.h"
 #include "llsdutil_math.h"
 #include "v4color.h"
 
@@ -60,18 +61,24 @@ LLTextureEntry* LLTextureEntry::newTextureEntry()
 //===============================================================
 LLTextureEntry::LLTextureEntry()
   : mMediaEntry(NULL)
+  , mSelected(false)
+  , mMaterialUpdatePending(false)
 {
 	init(LLUUID::null,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE);
 }
 
 LLTextureEntry::LLTextureEntry(const LLUUID& tex_id)
   : mMediaEntry(NULL)
+  , mSelected(false)
+  , mMaterialUpdatePending(false)
 {
 	init(tex_id,1.f,1.f,0.f,0.f,0.f,DEFAULT_BUMP_CODE);
 }
 
 LLTextureEntry::LLTextureEntry(const LLTextureEntry &rhs)
   : mMediaEntry(NULL)
+  , mSelected(false)
+  , mMaterialUpdatePending(false)
 {
 	mID = rhs.mID;
 	mScaleS = rhs.mScaleS;
@@ -83,6 +90,8 @@ LLTextureEntry::LLTextureEntry(const LLTextureEntry &rhs)
 	mBump = rhs.mBump;
 	mMediaFlags = rhs.mMediaFlags;
 	mGlow = rhs.mGlow;
+	mMaterialID = rhs.mMaterialID;
+	mMaterial = rhs.mMaterial;
 	if (rhs.mMediaEntry != NULL) {
 		// Make a copy
 		mMediaEntry = new LLMediaEntry(*rhs.mMediaEntry);
@@ -103,6 +112,8 @@ LLTextureEntry &LLTextureEntry::operator=(const LLTextureEntry &rhs)
 		mBump = rhs.mBump;
 		mMediaFlags = rhs.mMediaFlags;
 		mGlow = rhs.mGlow;
+		mMaterialID = rhs.mMaterialID;
+		mMaterial = rhs.mMaterial;
 		if (mMediaEntry != NULL) {
 			delete mMediaEntry;
 		}
@@ -130,6 +141,7 @@ void LLTextureEntry::init(const LLUUID& tex_id, F32 scale_s, F32 scale_t, F32 of
 	mBump = bump;
 	mMediaFlags = 0x0;
     mGlow = 0;
+	mMaterialID.clear();
 	
 	setColor(LLColor4(1.f, 1.f, 1.f, 1.f));
 	if (mMediaEntry != NULL) {
@@ -159,6 +171,7 @@ bool LLTextureEntry::operator!=(const LLTextureEntry &rhs) const
 	if (mBump != rhs.mBump) return (true);
 	if (mMediaFlags != rhs.mMediaFlags) return (true);
 	if (mGlow != rhs.mGlow) return (true);
+	if (mMaterialID != rhs.mMaterialID) return (true);
 	return(false);
 }
 
@@ -174,6 +187,7 @@ bool LLTextureEntry::operator==(const LLTextureEntry &rhs) const
 	if (mBump != rhs.mBump) return (false);
 	if (mMediaFlags != rhs.mMediaFlags) return false;
 	if (mGlow != rhs.mGlow) return false;
+	if (mMaterialID != rhs.mMaterialID) return (false);
 	return(true);
 }
 
@@ -523,6 +537,34 @@ S32 LLTextureEntry::setGlow(F32 glow)
 	return TEM_CHANGE_NONE;
 }
 
+S32 LLTextureEntry::setMaterialID(const LLMaterialID& pMaterialID)
+{
+	if ( (mMaterialID != pMaterialID) || (mMaterialUpdatePending && !mSelected) )
+	{
+		if (mSelected)
+		{
+			mMaterialUpdatePending = true;
+			mMaterialID = pMaterialID;
+			return TEM_CHANGE_NONE;
+		}
+
+		mMaterialUpdatePending = false;
+		mMaterialID = pMaterialID;
+		return TEM_CHANGE_TEXTURE;
+	}
+	return TEM_CHANGE_NONE;
+}
+
+S32 LLTextureEntry::setMaterialParams(const LLMaterialPtr pMaterialParams)
+{
+	if (mSelected)
+	{
+		mMaterialUpdatePending = true;
+	}
+	mMaterial = pMaterialParams;
+	return TEM_CHANGE_TEXTURE;
+}
+
 void LLTextureEntry::setMediaData(const LLMediaEntry &media_entry)
 {
     mMediaFlags |= MF_HAS_MEDIA;
diff --git a/indra/llprimitive/lltextureentry.h b/indra/llprimitive/lltextureentry.h
index 437b85e03ff02abc34b37ac31e955165a43c83c4..19edcaa27d079d9eca8ae30b0c57f9746ef67fa0 100755
--- a/indra/llprimitive/lltextureentry.h
+++ b/indra/llprimitive/lltextureentry.h
@@ -30,6 +30,8 @@
 #include "lluuid.h"
 #include "v4color.h"
 #include "llsd.h"
+#include "llmaterialid.h"
+#include "llmaterial.h"
 
 // These bits are used while unpacking TEM messages to tell which aspects of
 // the texture entry changed.
@@ -98,6 +100,10 @@ class LLTextureEntry
 
 	void init(const LLUUID& tex_id, F32 scale_s, F32 scale_t, F32 offset_s, F32 offset_t, F32 rotation, U8 bump);
 
+	bool hasPendingMaterialUpdate() const { return mMaterialUpdatePending; }
+	bool isSelected() const { return mSelected; }
+	bool setSelected(bool sel) { bool prev_sel = mSelected; mSelected = sel; return prev_sel; }
+
 	// These return a TEM_ flag from above to indicate if something changed.
 	S32  setID (const LLUUID &tex_id);
 	S32  setColor(const LLColor4 &color);
@@ -121,11 +127,19 @@ class LLTextureEntry
 	S32	 setTexGen(U8 texGen);
 	S32  setMediaTexGen(U8 media);
     S32  setGlow(F32 glow);
+	S32  setMaterialID(const LLMaterialID& pMaterialID);
+	S32  setMaterialParams(const LLMaterialPtr pMaterialParams);
 	
 	virtual const LLUUID &getID() const { return mID; }
 	const LLColor4 &getColor() const { return mColor; }
 	void getScale(F32 *s, F32 *t) const { *s = mScaleS; *t = mScaleT; }
+	F32  getScaleS() const { return mScaleS; }
+	F32  getScaleT() const { return mScaleT; }
+
 	void getOffset(F32 *s, F32 *t) const { *s = mOffsetS; *t = mOffsetT; }
+	F32  getOffsetS() const { return mOffsetS; }
+	F32  getOffsetT() const { return mOffsetT; }
+
 	F32  getRotation() const { return mRotation; }
 	void getRotation(F32 *theta) const { *theta = mRotation; }
 
@@ -136,9 +150,11 @@ class LLTextureEntry
  	U8	 getBumpShinyFullbright() const { return mBump; }
 
 	U8	 getMediaFlags() const { return mMediaFlags & TEM_MEDIA_MASK; }
-	U8	 getTexGen() const	{ return mMediaFlags & TEM_TEX_GEN_MASK; }
+	LLTextureEntry::e_texgen	 getTexGen() const	{ return LLTextureEntry::e_texgen(mMediaFlags & TEM_TEX_GEN_MASK); }
 	U8	 getMediaTexGen() const { return mMediaFlags; }
     F32  getGlow() const { return mGlow; }
+	const LLMaterialID& getMaterialID() const { return mMaterialID; };
+	const LLMaterialPtr getMaterialParams() const { return mMaterial; };
 
     // *NOTE: it is possible for hasMedia() to return true, but getMediaData() to return NULL.
     // CONVERSELY, it is also possible for hasMedia() to return false, but getMediaData()
@@ -188,11 +204,15 @@ class LLTextureEntry
 	static const char* TEXTURE_MEDIA_DATA_KEY;
 
 protected:
+	bool                mSelected;
 	LLUUID				mID;					// Texture GUID
 	LLColor4			mColor;
 	U8					mBump;					// Bump map, shiny, and fullbright
 	U8					mMediaFlags;			// replace with web page, movie, etc.
 	F32                 mGlow;
+	bool                mMaterialUpdatePending;
+	LLMaterialID        mMaterialID;
+	LLMaterialPtr		mMaterial;
 
 	// Note the media data is not sent via the same message structure as the rest of the TE
 	LLMediaEntry*		mMediaEntry;			// The media data for the face
diff --git a/indra/llrender/CMakeLists.txt b/indra/llrender/CMakeLists.txt
index 669b70aa433a25bc131b9d78f1d2573aed4cd6ee..dba12d048e5b6a663051f8b0f12dfdd0c54acbfd 100755
--- a/indra/llrender/CMakeLists.txt
+++ b/indra/llrender/CMakeLists.txt
@@ -92,7 +92,7 @@ if (BUILD_HEADLESS)
 
   set_property(TARGET llrenderheadless
     PROPERTY COMPILE_DEFINITIONS LL_MESA=1 LL_MESA_HEADLESS=1
-    )
+      )
 
   target_link_libraries(llrenderheadless
     ${LLCOMMON_LIBRARIES}
diff --git a/indra/llrender/llgl.cpp b/indra/llrender/llgl.cpp
index 6c798aa4ed081b7bdce3cde61d6d6539802ed727..088ba95b7502a282261c6320c1f64296135cbff0 100755
--- a/indra/llrender/llgl.cpp
+++ b/indra/llrender/llgl.cpp
@@ -86,7 +86,7 @@ void APIENTRY gl_debug_callback(GLenum source,
 	}
 	else
 	{
-		llwarns << "----- GL WARNING -------" << llendl;		
+		llwarns << "----- GL WARNING -------" << llendl;
 	}
 	llwarns << "Type: " << std::hex << type << llendl;
 	llwarns << "ID: " << std::hex << id << llendl;
@@ -216,6 +216,11 @@ PFNGLGETQUERYIVARBPROC glGetQueryivARB = NULL;
 PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB = NULL;
 PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB = NULL;
 
+// GL_ARB_timer_query
+PFNGLQUERYCOUNTERPROC glQueryCounter = NULL;
+PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v = NULL;
+PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v = NULL;
+
 // GL_ARB_point_parameters
 PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB = NULL;
 PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB = NULL;
@@ -421,6 +426,7 @@ LLGLManager::LLGLManager() :
 	mHasFragmentShader(FALSE),
 	mNumTextureImageUnits(0),
 	mHasOcclusionQuery(FALSE),
+	mHasTimerQuery(FALSE),
 	mHasOcclusionQuery2(FALSE),
 	mHasPointParameters(FALSE),
 	mHasDrawBuffers(FALSE),
@@ -445,7 +451,9 @@ LLGLManager::LLGLManager() :
 	mIsGFFX(FALSE),
 	mATIOffsetVerticalLines(FALSE),
 	mATIOldDriver(FALSE),
-
+#if LL_DARWIN
+	mIsMobileGF(FALSE),
+#endif
 	mHasRequirements(TRUE),
 
 	mHasSeparateSpecularColor(FALSE),
@@ -637,6 +645,13 @@ bool LLGLManager::initGL()
 		{
 			mIsGF3 = TRUE;
 		}
+#if LL_DARWIN
+		else if ((mGLRenderer.find("9400M") != std::string::npos)
+			  || (mGLRenderer.find("9600M") != std::string::npos))
+		{
+			mIsMobileGF = TRUE;
+		}
+#endif
 
 	}
 	else if (mGLVendor.find("INTEL") != std::string::npos
@@ -745,12 +760,13 @@ bool LLGLManager::initGL()
 	{ //using multisample textures on ATI results in black screen for some reason
 		mHasTextureMultisample = FALSE;
 	}
-#endif
+
 
 	if (mIsIntel && mGLVersion <= 3.f)
 	{ //never try to use framebuffer objects on older intel drivers (crashy)
 		mHasFramebufferObject = FALSE;
 	}
+#endif
 
 	if (mHasFramebufferObject)
 	{
@@ -947,13 +963,15 @@ void LLGLManager::initExtensions()
 	mHasARBEnvCombine = ExtensionExists("GL_ARB_texture_env_combine", gGLHExts.mSysExts);
 	mHasCompressedTextures = glh_init_extensions("GL_ARB_texture_compression");
 	mHasOcclusionQuery = ExtensionExists("GL_ARB_occlusion_query", gGLHExts.mSysExts);
+	mHasTimerQuery = ExtensionExists("GL_ARB_timer_query", gGLHExts.mSysExts);
 	mHasOcclusionQuery2 = ExtensionExists("GL_ARB_occlusion_query2", gGLHExts.mSysExts);
 	mHasVertexBufferObject = ExtensionExists("GL_ARB_vertex_buffer_object", gGLHExts.mSysExts);
 	mHasVertexArrayObject = ExtensionExists("GL_ARB_vertex_array_object", gGLHExts.mSysExts);
 	mHasSync = ExtensionExists("GL_ARB_sync", gGLHExts.mSysExts);
 	mHasMapBufferRange = ExtensionExists("GL_ARB_map_buffer_range", gGLHExts.mSysExts);
 	mHasFlushBufferRange = ExtensionExists("GL_APPLE_flush_buffer_range", gGLHExts.mSysExts);
-	mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts);
+	//mHasDepthClamp = ExtensionExists("GL_ARB_depth_clamp", gGLHExts.mSysExts) || ExtensionExists("GL_NV_depth_clamp", gGLHExts.mSysExts);
+	mHasDepthClamp = FALSE;
 	// mask out FBO support when packed_depth_stencil isn't there 'cause we need it for LLRenderTarget -Brad
 #ifdef GL_ARB_framebuffer_object
 	mHasFramebufferObject = ExtensionExists("GL_ARB_framebuffer_object", gGLHExts.mSysExts);
@@ -963,6 +981,15 @@ void LLGLManager::initExtensions()
 							ExtensionExists("GL_EXT_framebuffer_multisample", gGLHExts.mSysExts) &&
 							ExtensionExists("GL_EXT_packed_depth_stencil", gGLHExts.mSysExts);
 #endif
+#ifdef GL_EXT_texture_sRGB
+	mHassRGBTexture = ExtensionExists("GL_EXT_texture_sRGB", gGLHExts.mSysExts);
+#endif
+	
+#ifdef GL_ARB_framebuffer_sRGB
+	mHassRGBFramebuffer = ExtensionExists("GL_ARB_framebuffer_sRGB", gGLHExts.mSysExts);
+#else
+	mHassRGBFramebuffer = ExtensionExists("GL_EXT_framebuffer_sRGB", gGLHExts.mSysExts);
+#endif
 	
 	mHasMipMapGeneration = mHasFramebufferObject || mGLVersion >= 1.4f;
 
@@ -1253,6 +1280,13 @@ void LLGLManager::initExtensions()
 		glGetQueryObjectivARB = (PFNGLGETQUERYOBJECTIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjectivARB");
 		glGetQueryObjectuivARB = (PFNGLGETQUERYOBJECTUIVARBPROC)GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjectuivARB");
 	}
+	if (mHasTimerQuery)
+	{
+		llinfos << "initExtensions() TimerQuery-related procs..." << llendl;
+		glQueryCounter = (PFNGLQUERYCOUNTERPROC) GLH_EXT_GET_PROC_ADDRESS("glQueryCounter");
+		glGetQueryObjecti64v = (PFNGLGETQUERYOBJECTI64VPROC) GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjecti64v");
+		glGetQueryObjectui64v = (PFNGLGETQUERYOBJECTUI64VPROC) GLH_EXT_GET_PROC_ADDRESS("glGetQueryObjectui64v");
+	}
 	if (mHasPointParameters)
 	{
 		llinfos << "initExtensions() PointParameters-related procs..." << llendl;
diff --git a/indra/llrender/llgl.h b/indra/llrender/llgl.h
index d70e764769a12e7854939dc36bf3d1071a5b34c4..60597fd090943c42d6a8eeaaf38a216eb55aac5a 100755
--- a/indra/llrender/llgl.h
+++ b/indra/llrender/llgl.h
@@ -98,6 +98,7 @@ class LLGLManager
 	BOOL mHasFragmentShader;
 	S32  mNumTextureImageUnits;
 	BOOL mHasOcclusionQuery;
+	BOOL mHasTimerQuery;
 	BOOL mHasOcclusionQuery2;
 	BOOL mHasPointParameters;
 	BOOL mHasDrawBuffers;
@@ -115,6 +116,8 @@ class LLGLManager
 	BOOL mHasARBEnvCombine;
 	BOOL mHasCubeMap;
 	BOOL mHasDebugOutput;
+	BOOL mHassRGBTexture;
+	BOOL mHassRGBFramebuffer;
 
 	// Vendor-specific extensions
 	BOOL mIsATI;
@@ -126,6 +129,11 @@ class LLGLManager
 	BOOL mATIOffsetVerticalLines;
 	BOOL mATIOldDriver;
 
+#if LL_DARWIN
+	// Needed to distinguish problem cards on older Macs that break with Materials
+	BOOL mIsMobileGF;
+#endif
+	
 	// Whether this version of GL is good enough for SL to use
 	BOOL mHasRequirements;
 
diff --git a/indra/llrender/llglheaders.h b/indra/llrender/llglheaders.h
index 509de51f4dfc4261ab7c22cf47cb817288dbd189..dace57295350d382d548ca6d50f605ff084ca259 100755
--- a/indra/llrender/llglheaders.h
+++ b/indra/llrender/llglheaders.h
@@ -116,6 +116,11 @@ extern PFNGLGETQUERYIVARBPROC glGetQueryivARB;
 extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB;
 extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB;
 
+// GL_ARB_timer_query
+extern PFNGLQUERYCOUNTERPROC glQueryCounter;
+extern PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v;
+extern PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v;
+
 // GL_ARB_point_parameters
 extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB;
 extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB;
@@ -378,6 +383,11 @@ extern PFNGLGETQUERYIVARBPROC glGetQueryivARB;
 extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB;
 extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB;
 
+// GL_ARB_timer_query
+extern PFNGLQUERYCOUNTERPROC glQueryCounter;
+extern PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v;
+extern PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v;
+
 // GL_ARB_point_parameters
 extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB;
 extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB;
@@ -619,6 +629,12 @@ extern PFNGLGETQUERYIVARBPROC glGetQueryivARB;
 extern PFNGLGETQUERYOBJECTIVARBPROC glGetQueryObjectivARB;
 extern PFNGLGETQUERYOBJECTUIVARBPROC glGetQueryObjectuivARB;
 
+// GL_ARB_timer_query
+extern PFNGLQUERYCOUNTERPROC glQueryCounter;
+extern PFNGLGETQUERYOBJECTI64VPROC glGetQueryObjecti64v;
+extern PFNGLGETQUERYOBJECTUI64VPROC glGetQueryObjectui64v;
+
+
 // GL_ARB_point_parameters
 extern PFNGLPOINTPARAMETERFARBPROC glPointParameterfARB;
 extern PFNGLPOINTPARAMETERFVARBPROC glPointParameterfvARB;
diff --git a/indra/llrender/llglslshader.cpp b/indra/llrender/llglslshader.cpp
index 7cbf39096ec8fbbf9993e4fcd99e556037ee74ca..ac16e30796a96d4e27190151a7344f2a92a0afc7 100755
--- a/indra/llrender/llglslshader.cpp
+++ b/indra/llrender/llglslshader.cpp
@@ -53,6 +53,12 @@ GLhandleARB LLGLSLShader::sCurBoundShader = 0;
 LLGLSLShader* LLGLSLShader::sCurBoundShaderPtr = NULL;
 S32 LLGLSLShader::sIndexedTextureChannels = 0;
 bool LLGLSLShader::sNoFixedFunction = false;
+bool LLGLSLShader::sProfileEnabled = false;
+std::set<LLGLSLShader*> LLGLSLShader::sInstances;
+U64 LLGLSLShader::sTotalTimeElapsed = 0;
+U32 LLGLSLShader::sTotalTrianglesDrawn = 0;
+U64 LLGLSLShader::sTotalSamplesDrawn = 0;
+U32 LLGLSLShader::sTotalDrawCalls = 0;
 
 //UI shader -- declared here so llui_libtest will link properly
 LLGLSLShader	gUIProgram;
@@ -87,19 +93,240 @@ LLShaderFeatures::LLShaderFeatures()
 //===============================
 // LLGLSL Shader implementation
 //===============================
+
+//static
+void LLGLSLShader::initProfile()
+{
+	sProfileEnabled = true;
+	sTotalTimeElapsed = 0;
+	sTotalTrianglesDrawn = 0;
+	sTotalSamplesDrawn = 0;
+	sTotalDrawCalls = 0;
+
+	for (std::set<LLGLSLShader*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
+	{
+		(*iter)->clearStats();
+	}
+}
+
+
+struct LLGLSLShaderCompareTimeElapsed
+{
+		bool operator()(const LLGLSLShader* const& lhs, const LLGLSLShader* const& rhs)
+		{
+			return lhs->mTimeElapsed < rhs->mTimeElapsed;
+		}
+};
+
+//static
+void LLGLSLShader::finishProfile()
+{
+	sProfileEnabled = false;
+
+	std::vector<LLGLSLShader*> sorted;
+
+	for (std::set<LLGLSLShader*>::iterator iter = sInstances.begin(); iter != sInstances.end(); ++iter)
+	{
+		sorted.push_back(*iter);
+	}
+
+	std::sort(sorted.begin(), sorted.end(), LLGLSLShaderCompareTimeElapsed());
+
+	for (std::vector<LLGLSLShader*>::iterator iter = sorted.begin(); iter != sorted.end(); ++iter)
+	{
+		(*iter)->dumpStats();
+	}
+
+	llinfos << "-----------------------------------" << llendl;
+	llinfos << "Total rendering time: " << llformat("%.4f ms", sTotalTimeElapsed/1000000.f) << llendl;
+	llinfos << "Total samples drawn: " << llformat("%.4f million", sTotalSamplesDrawn/1000000.f) << llendl;
+	llinfos << "Total triangles drawn: " << llformat("%.3f million", sTotalTrianglesDrawn/1000000.f) << llendl;
+}
+
+void LLGLSLShader::clearStats()
+{
+	mTrianglesDrawn = 0;
+	mTimeElapsed = 0;
+	mSamplesDrawn = 0;
+	mDrawCalls = 0;
+	mTextureStateFetched = false;
+	mTextureMagFilter.clear();
+	mTextureMinFilter.clear();
+}
+
+void LLGLSLShader::dumpStats()
+{
+	if (mDrawCalls > 0)
+	{
+		llinfos << "=============================================" << llendl;
+		llinfos << mName << llendl;
+		for (U32 i = 0; i < mShaderFiles.size(); ++i)
+		{
+			llinfos << mShaderFiles[i].first << llendl;
+		}
+		for (U32 i = 0; i < mTexture.size(); ++i)
+		{
+			GLint idx = mTexture[i];
+			
+			if (idx >= 0)
+			{
+				GLint uniform_idx = getUniformLocation(i);
+				llinfos << mUniformNameMap[uniform_idx] << " - " << std::hex << mTextureMagFilter[i] << "/" << mTextureMinFilter[i] << std::dec << llendl;
+			}
+		}
+		llinfos << "=============================================" << llendl;
+
+		F32 ms = mTimeElapsed/1000000.f;
+		F32 seconds = ms/1000.f;
+
+		F32 pct_tris = (F32) mTrianglesDrawn/(F32)sTotalTrianglesDrawn*100.f;
+		F32 tris_sec = (F32) (mTrianglesDrawn/1000000.0);
+		tris_sec /= seconds;
+
+		F32 pct_samples = (F32) ((F64)mSamplesDrawn/(F64)sTotalSamplesDrawn)*100.f;
+		F32 samples_sec = (F32) mSamplesDrawn/1000000000.0;
+		samples_sec /= seconds;
+
+		F32 pct_calls = (F32) mDrawCalls/(F32)sTotalDrawCalls*100.f;
+		U32 avg_batch = mTrianglesDrawn/mDrawCalls;
+
+		llinfos << "Triangles Drawn: " << mTrianglesDrawn <<  " " << llformat("(%.2f pct of total, %.3f million/sec)", pct_tris, tris_sec ) << llendl;
+		llinfos << "Draw Calls: " << mDrawCalls << " " << llformat("(%.2f pct of total, avg %d tris/call)", pct_calls, avg_batch) << llendl;
+		llinfos << "SamplesDrawn: " << mSamplesDrawn << " " << llformat("(%.2f pct of total, %.3f billion/sec)", pct_samples, samples_sec) << llendl;
+		llinfos << "Time Elapsed: " << mTimeElapsed << " " << llformat("(%.2f pct of total, %.5f ms)\n", (F32) ((F64)mTimeElapsed/(F64)sTotalTimeElapsed)*100.f, ms) << llendl;
+	}
+}
+
+//static
+void LLGLSLShader::startProfile()
+{
+	if (sProfileEnabled && sCurBoundShaderPtr)
+	{
+		sCurBoundShaderPtr->placeProfileQuery();
+	}
+
+}
+
+//static
+void LLGLSLShader::stopProfile(U32 count, U32 mode)
+{
+	if (sProfileEnabled)
+	{
+		sCurBoundShaderPtr->readProfileQuery(count, mode);
+	}
+}
+
+void LLGLSLShader::placeProfileQuery()
+{
+#if !LL_DARWIN
+	if (mTimerQuery == 0)
+	{
+		glGenQueriesARB(1, &mTimerQuery);
+	}
+
+	if (!mTextureStateFetched)
+	{
+		mTextureStateFetched = true;
+		mTextureMagFilter.resize(mTexture.size());
+		mTextureMinFilter.resize(mTexture.size());
+
+		U32 cur_active = gGL.getCurrentTexUnitIndex();
+
+		for (U32 i = 0; i < mTexture.size(); ++i)
+		{
+			GLint idx = mTexture[i];
+
+			if (idx >= 0)
+			{
+				gGL.getTexUnit(idx)->activate();
+
+				U32 mag = 0xFFFFFFFF;
+				U32 min = 0xFFFFFFFF;
+
+				U32 type = LLTexUnit::getInternalType(gGL.getTexUnit(idx)->getCurrType());
+
+				glGetTexParameteriv(type, GL_TEXTURE_MAG_FILTER, (GLint*) &mag);
+				glGetTexParameteriv(type, GL_TEXTURE_MIN_FILTER, (GLint*) &min);
+
+				mTextureMagFilter[i] = mag;
+				mTextureMinFilter[i] = min;
+			}
+		}
+
+		gGL.getTexUnit(cur_active)->activate();
+	}
+
+
+	glBeginQueryARB(GL_SAMPLES_PASSED, 1);
+	glBeginQueryARB(GL_TIME_ELAPSED, mTimerQuery);
+#endif
+}
+
+void LLGLSLShader::readProfileQuery(U32 count, U32 mode)
+{
+#if !LL_DARWIN
+	glEndQueryARB(GL_TIME_ELAPSED);
+	glEndQueryARB(GL_SAMPLES_PASSED);
+	
+	U64 time_elapsed = 0;
+	glGetQueryObjectui64v(mTimerQuery, GL_QUERY_RESULT, &time_elapsed);
+
+	U64 samples_passed = 0;
+	glGetQueryObjectui64v(1, GL_QUERY_RESULT, &samples_passed);
+
+	sTotalTimeElapsed += time_elapsed;
+	mTimeElapsed += time_elapsed;
+
+	sTotalSamplesDrawn += samples_passed;
+	mSamplesDrawn += samples_passed;
+
+	U32 tri_count = 0;
+	switch (mode)
+	{
+		case LLRender::TRIANGLES: tri_count = count/3; break;
+		case LLRender::TRIANGLE_FAN: tri_count = count-2; break;
+		case LLRender::TRIANGLE_STRIP: tri_count = count-2; break;
+		default: tri_count = count; break; //points lines etc just use primitive count
+	}
+
+	mTrianglesDrawn += tri_count;
+	sTotalTrianglesDrawn += tri_count;
+
+	sTotalDrawCalls++;
+	mDrawCalls++;
+#endif
+}
+
+
+
 LLGLSLShader::LLGLSLShader()
-	: mProgramObject(0), mActiveTextureChannels(0), mShaderLevel(0), mShaderGroup(SG_DEFAULT), mUniformsDirty(FALSE)
+	: mProgramObject(0), 
+	  mAttributeMask(0),
+	  mTotalUniformSize(0),
+	  mActiveTextureChannels(0), 
+	  mShaderLevel(0), 
+	  mShaderGroup(SG_DEFAULT), 
+	  mUniformsDirty(FALSE),
+	  mTimerQuery(0)
 {
+	
+}
 
+LLGLSLShader::~LLGLSLShader()
+{
+	
 }
 
 void LLGLSLShader::unload()
 {
+	sInstances.erase(this);
+
 	stop_glerror();
 	mAttribute.clear();
 	mTexture.clear();
 	mUniform.clear();
 	mShaderFiles.clear();
+	mDefines.clear();
 
 	if (mProgramObject)
 	{
@@ -133,6 +360,8 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
 								U32 varying_count,
 								const char** varyings)
 {
+	sInstances.insert(this);
+
 	//reloading, reset matrix hash values
 	for (U32 i = 0; i < LLRender::NUM_MATRIX_MODES; ++i)
 	{
@@ -150,7 +379,7 @@ BOOL LLGLSLShader::createShader(vector<string> * attributes,
 	vector< pair<string,GLenum> >::iterator fileIter = mShaderFiles.begin();
 	for ( ; fileIter != mShaderFiles.end(); fileIter++ )
 	{
-		GLhandleARB shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second, mFeatures.mIndexedTextureChannels);
+		GLhandleARB shaderhandle = LLShaderMgr::instance()->loadShaderFile((*fileIter).first, mShaderLevel, (*fileIter).second, &mDefines, mFeatures.mIndexedTextureChannels);
 		LL_DEBUGS("ShaderLoading") << "SHADER FILE: " << (*fileIter).first << " mShaderLevel=" << mShaderLevel << LL_ENDL;
 		if (shaderhandle > 0)
 		{
@@ -285,6 +514,8 @@ BOOL LLGLSLShader::mapAttributes(const vector<string> * attributes)
 	if (res)
 	{ //read back channel locations
 
+		mAttributeMask = 0;
+
 		//read back reserved channels first
 		for (U32 i = 0; i < LLShaderMgr::instance()->mReservedAttribs.size(); i++)
 		{
@@ -293,6 +524,7 @@ BOOL LLGLSLShader::mapAttributes(const vector<string> * attributes)
 			if (index != -1)
 			{
 				mAttribute[i] = index;
+				mAttributeMask |= 1 << i;
 				LL_DEBUGS("ShaderLoading") << "Attribute " << name << " assigned to channel " << index << LL_ENDL;
 			}
 		}
@@ -325,11 +557,56 @@ void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms)
 
 	GLenum type;
 	GLsizei length;
-	GLint size;
+	GLint size = -1;
 	char name[1024];		/* Flawfinder: ignore */
 	name[0] = 0;
 
+
 	glGetActiveUniformARB(mProgramObject, index, 1024, &length, &size, &type, (GLcharARB *)name);
+#if !LL_DARWIN
+	if (size > 0)
+	{
+		switch(type)
+		{
+			case GL_FLOAT_VEC2: size *= 2; break;
+			case GL_FLOAT_VEC3: size *= 3; break;
+			case GL_FLOAT_VEC4: size *= 4; break;
+			case GL_DOUBLE: size *= 2; break;
+			case GL_DOUBLE_VEC2: size *= 2; break;
+			case GL_DOUBLE_VEC3: size *= 6; break;
+			case GL_DOUBLE_VEC4: size *= 8; break;
+			case GL_INT_VEC2: size *= 2; break;
+			case GL_INT_VEC3: size *= 3; break;
+			case GL_INT_VEC4: size *= 4; break;
+			case GL_UNSIGNED_INT_VEC2: size *= 2; break;
+			case GL_UNSIGNED_INT_VEC3: size *= 3; break;
+			case GL_UNSIGNED_INT_VEC4: size *= 4; break;
+			case GL_BOOL_VEC2: size *= 2; break;
+			case GL_BOOL_VEC3: size *= 3; break;
+			case GL_BOOL_VEC4: size *= 4; break;
+			case GL_FLOAT_MAT2: size *= 4; break;
+			case GL_FLOAT_MAT3: size *= 9; break;
+			case GL_FLOAT_MAT4: size *= 16; break;
+			case GL_FLOAT_MAT2x3: size *= 6; break;
+			case GL_FLOAT_MAT2x4: size *= 8; break;
+			case GL_FLOAT_MAT3x2: size *= 6; break;
+			case GL_FLOAT_MAT3x4: size *= 12; break;
+			case GL_FLOAT_MAT4x2: size *= 8; break;
+			case GL_FLOAT_MAT4x3: size *= 12; break;
+			case GL_DOUBLE_MAT2: size *= 8; break;
+			case GL_DOUBLE_MAT3: size *= 18; break;
+			case GL_DOUBLE_MAT4: size *= 32; break;
+			case GL_DOUBLE_MAT2x3: size *= 12; break;
+			case GL_DOUBLE_MAT2x4: size *= 16; break;
+			case GL_DOUBLE_MAT3x2: size *= 12; break;
+			case GL_DOUBLE_MAT3x4: size *= 24; break;
+			case GL_DOUBLE_MAT4x2: size *= 16; break;
+			case GL_DOUBLE_MAT4x3: size *= 24; break;
+		}
+		mTotalUniformSize += size;
+	}
+#endif
+
 	S32 location = glGetUniformLocationARB(mProgramObject, name);
 	if (location != -1)
 	{
@@ -342,6 +619,7 @@ void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms)
 		}
 
 		mUniformMap[name] = location;
+		mUniformNameMap[location] = name;
 		LL_DEBUGS("ShaderLoading") << "Uniform " << name << " is at location " << location << LL_ENDL;
 	
 		//find the index of this uniform
@@ -372,11 +650,21 @@ void LLGLSLShader::mapUniform(GLint index, const vector<string> * uniforms)
 			}
 		}
 	}
- }
+}
+
+void LLGLSLShader::addPermutation(std::string name, std::string value)
+{
+	mDefines[name] = value;
+}
+
+void LLGLSLShader::removePermutation(std::string name)
+{
+	mDefines[name].erase();
+}
 
 GLint LLGLSLShader::mapUniformTextureChannel(GLint location, GLenum type)
 {
-	if (type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB ||
+	if ((type >= GL_SAMPLER_1D_ARB && type <= GL_SAMPLER_2D_RECT_SHADOW_ARB) ||
 		type == GL_SAMPLER_2D_MULTISAMPLE)
 	{	//this here is a texture
 		glUniform1iARB(location, mActiveTextureChannels);
@@ -390,9 +678,11 @@ BOOL LLGLSLShader::mapUniforms(const vector<string> * uniforms)
 {
 	BOOL res = TRUE;
 	
+	mTotalUniformSize = 0;
 	mActiveTextureChannels = 0;
 	mUniform.clear();
 	mUniformMap.clear();
+	mUniformNameMap.clear();
 	mTexture.clear();
 	mValue.clear();
 	//initialize arrays
@@ -413,6 +703,7 @@ BOOL LLGLSLShader::mapUniforms(const vector<string> * uniforms)
 
 	unbind();
 
+	LL_DEBUGS("ShaderLoading") << "Total Uniform Size: " << mTotalUniformSize << llendl;
 	return res;
 }
 
@@ -471,6 +762,58 @@ void LLGLSLShader::bindNoShader(void)
 	}
 }
 
+S32 LLGLSLShader::bindTexture(const std::string &uniform, LLTexture *texture, LLTexUnit::eTextureType mode)
+{
+	S32 channel = 0;
+	channel = getUniformLocation(uniform);
+	
+	return bindTexture(channel, texture, mode);
+}
+
+S32 LLGLSLShader::bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextureType mode)
+{
+	if (uniform < 0 || uniform >= (S32)mTexture.size())
+	{
+		UNIFORM_ERRS << "Uniform out of range: " << uniform << LL_ENDL;
+		return -1;
+	}
+	
+	uniform = mTexture[uniform];
+	
+	if (uniform > -1)
+	{
+		gGL.getTexUnit(uniform)->bind(texture, mode);
+	}
+	
+	return uniform;
+}
+
+S32 LLGLSLShader::unbindTexture(const std::string &uniform, LLTexUnit::eTextureType mode)
+{
+	S32 channel = 0;
+	channel = getUniformLocation(uniform);
+	
+	return unbindTexture(channel);
+}
+
+S32 LLGLSLShader::unbindTexture(S32 uniform, LLTexUnit::eTextureType mode)
+{
+	if (uniform < 0 || uniform >= (S32)mTexture.size())
+	{
+		UNIFORM_ERRS << "Uniform out of range: " << uniform << LL_ENDL;
+		return -1;
+	}
+	
+	uniform = mTexture[uniform];
+	
+	if (uniform > -1)
+	{
+		gGL.getTexUnit(uniform)->unbind(mode);
+	}
+	
+	return uniform;
+}
+
 S32 LLGLSLShader::enableTexture(S32 uniform, LLTexUnit::eTextureType mode)
 {
 	if (uniform < 0 || uniform >= (S32)mTexture.size())
@@ -857,6 +1200,23 @@ void LLGLSLShader::uniform1i(const string& uniform, GLint v)
 	}
 }
 
+void LLGLSLShader::uniform2i(const string& uniform, GLint i, GLint j)
+{
+	GLint location = getUniformLocation(uniform);
+				
+	if (location >= 0)
+	{
+		std::map<GLint, LLVector4>::iterator iter = mValue.find(location);
+		LLVector4 vec(i,j,0.f,0.f);
+		if (iter == mValue.end() || shouldChange(iter->second,vec))
+		{
+			glUniform2iARB(location, i, j);
+			mValue[location] = vec;
+		}
+	}
+}
+
+
 void LLGLSLShader::uniform1f(const string& uniform, GLfloat v)
 {
 	GLint location = getUniformLocation(uniform);
diff --git a/indra/llrender/llglslshader.h b/indra/llrender/llglslshader.h
index cf21101e35a2b064d9d121e826589b7f2a4435c9..eabdb9fc927c8a24680303b55a5b0704566480b1 100755
--- a/indra/llrender/llglslshader.h
+++ b/indra/llrender/llglslshader.h
@@ -67,14 +67,29 @@ class LLGLSLShader
 		SG_WATER
 	};
 	
+	static std::set<LLGLSLShader*> sInstances;
+	static bool sProfileEnabled;
+
 	LLGLSLShader();
+	~LLGLSLShader();
 
 	static GLhandleARB sCurBoundShader;
 	static LLGLSLShader* sCurBoundShaderPtr;
 	static S32 sIndexedTextureChannels;
 	static bool sNoFixedFunction;
 
+	static void initProfile();
+	static void finishProfile();
+
+	static void startProfile();
+	static void stopProfile(U32 count, U32 mode);
+
 	void unload();
+	void clearStats();
+	void dumpStats();
+	void placeProfileQuery();
+	void readProfileQuery(U32 count, U32 mode);
+
 	BOOL createShader(std::vector<std::string> * attributes,
 						std::vector<std::string> * uniforms,
 						U32 varying_count = 0,
@@ -96,6 +111,7 @@ class LLGLSLShader
 	void uniform3fv(U32 index, U32 count, const GLfloat* v);
 	void uniform4fv(U32 index, U32 count, const GLfloat* v);
 	void uniform1i(const std::string& uniform, GLint i);
+	void uniform2i(const std::string& uniform, GLint i, GLint j);
 	void uniform1f(const std::string& uniform, GLfloat v);
 	void uniform2f(const std::string& uniform, GLfloat x, GLfloat y);
 	void uniform3f(const std::string& uniform, GLfloat x, GLfloat y, GLfloat z);
@@ -123,12 +139,22 @@ class LLGLSLShader
 	GLint getAttribLocation(U32 attrib);
 	GLint mapUniformTextureChannel(GLint location, GLenum type);
 	
+	void addPermutation(std::string name, std::string value);
+	void removePermutation(std::string name);
+	
 	//enable/disable texture channel for specified uniform
 	//if given texture uniform is active in the shader, 
 	//the corresponding channel will be active upon return
 	//returns channel texture is enabled in from [0-MAX)
 	S32 enableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
-	S32 disableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE); 
+	S32 disableTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
+	
+	// bindTexture returns the texture unit we've bound the texture to.
+	// You can reuse the return value to unbind a texture when required.
+	S32 bindTexture(const std::string& uniform, LLTexture *texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
+	S32 bindTexture(S32 uniform, LLTexture *texture, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
+	S32 unbindTexture(const std::string& uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
+	S32 unbindTexture(S32 uniform, LLTexUnit::eTextureType mode = LLTexUnit::TT_TEXTURE);
 	
     BOOL link(BOOL suppress_errors = FALSE);
 	void bind();
@@ -142,10 +168,13 @@ class LLGLSLShader
 
 	GLhandleARB mProgramObject;
 	std::vector<GLint> mAttribute; //lookup table of attribute enum to attribute channel
+	U32 mAttributeMask;  //mask of which reserved attributes are set (lines up with LLVertexBuffer::getTypeMask())
 	std::vector<GLint> mUniform;   //lookup table of uniform enum to uniform location
 	std::map<std::string, GLint> mUniformMap;  //lookup map of uniform name to uniform location
+	std::map<GLint, std::string> mUniformNameMap; //lookup map of uniform location to uniform name
 	std::map<GLint, LLVector4> mValue; //lookup map of uniform location to last known value
 	std::vector<GLint> mTexture;
+	S32 mTotalUniformSize;
 	S32 mActiveTextureChannels;
 	S32 mShaderLevel;
 	S32 mShaderGroup;
@@ -153,6 +182,23 @@ class LLGLSLShader
 	LLShaderFeatures mFeatures;
 	std::vector< std::pair< std::string, GLenum > > mShaderFiles;
 	std::string mName;
+	boost::unordered_map<std::string, std::string> mDefines;
+
+	//statistcis for profiling shader performance
+	U32 mTimerQuery;
+	U64 mTimeElapsed;
+	static U64 sTotalTimeElapsed;
+	U32 mTrianglesDrawn;
+	static U32 sTotalTrianglesDrawn;
+	U64 mSamplesDrawn;
+	static U64 sTotalSamplesDrawn;
+	U32 mDrawCalls;
+	static U32 sTotalDrawCalls;
+
+	bool mTextureStateFetched;
+	std::vector<U32> mTextureMagFilter;
+	std::vector<U32> mTextureMinFilter;
+	
 };
 
 //UI shader (declared here so llui_libtest will link properly)
diff --git a/indra/llrender/llimagegl.cpp b/indra/llrender/llimagegl.cpp
index 5c171d372c250a9336ad4952818c04a96701d5e3..38764eba239e6b04ec8f304bba6ee05980a407e5 100644
--- a/indra/llrender/llimagegl.cpp
+++ b/indra/llrender/llimagegl.cpp
@@ -748,12 +748,16 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 				S32 height = getHeight(mCurrentDiscardLevel);
 				S32 nummips = mMaxDiscardLevel - mCurrentDiscardLevel + 1;
 				S32 w = width, h = height;
+
+
+				const U8* new_data = 0;
+				(void)new_data;
+
 				const U8* prev_mip_data = 0;
 				const U8* cur_mip_data = 0;
 #ifdef SHOW_ASSERT
 				S32 cur_mip_size = 0;
 #endif
-				
 				mMipLevels = nummips;
 
 				for (int m=0; m<nummips; m++)
@@ -773,14 +777,22 @@ void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
 						llassert(cur_mip_size == bytes*4);
 #endif
 						U8* new_data = new U8[bytes];
+
+#ifdef SHOW_ASSERT
+						llassert(prev_mip_data);
+						llassert(cur_mip_size == bytes*4);
 						llassert_always(new_data);
+#endif
+
 						LLImageBase::generateMip(prev_mip_data, new_data, w, h, mComponents);
 						cur_mip_data = new_data;
 #ifdef SHOW_ASSERT
 						cur_mip_size = bytes; 
 #endif
+
 					}
 					llassert(w > 0 && h > 0 && cur_mip_data);
+					(void)cur_mip_data;
 					{
 // 						LLFastTimer t1(FTM_TEMP4);
 						if(mFormatSwapBytes)
@@ -1119,30 +1131,30 @@ void LLImageGL::deleteTextures(LLTexUnit::eTextureType type, U32 format, S32 mip
 			default:
 			{
 				if (type == LLTexUnit::TT_CUBE_MAP || mip_levels == -1)
-				{ //unknown internal format or unknown number of mip levels, not safe to reuse
-					glDeleteTextures(numTextures, textures);
-				}
-				else
-				{
-					for (S32 i = 0; i < numTextures; ++i)
-					{ //remove texture from VRAM by setting its size to zero
+		{ //unknown internal format or unknown number of mip levels, not safe to reuse
+			glDeleteTextures(numTextures, textures);
+		}
+		else
+		{
+			for (S32 i = 0; i < numTextures; ++i)
+			{ //remove texture from VRAM by setting its size to zero
 
-						for (S32 j = 0; j <= mip_levels; j++)
-						{
-							gGL.getTexUnit(0)->bindManual(type, textures[i]);
+				for (S32 j = 0; j <= mip_levels; j++)
+				{
+					gGL.getTexUnit(0)->bindManual(type, textures[i]);
 							U32 internal_type = LLTexUnit::getInternalType(type);
 							glTexImage2D(internal_type, j, format, 0, 0, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
 							stop_glerror();
-						}
+				}
 
-						llassert(std::find(sDeadTextureList[type][format].begin(),
-							sDeadTextureList[type][format].end(), textures[i]) == 
-							sDeadTextureList[type][format].end());
+				llassert(std::find(sDeadTextureList[type][format].begin(),
+								   sDeadTextureList[type][format].end(), textures[i]) == 
+								   sDeadTextureList[type][format].end());
 
-						sDeadTextureList[type][format].push_back(textures[i]);
-					}	
-				}				
-			}
+				sDeadTextureList[type][format].push_back(textures[i]);
+			}	
+		}
+	}
 			break;
 		}
 	}
diff --git a/indra/llrender/llrender.h b/indra/llrender/llrender.h
index 78a310e525fbe8e8494d0d22f325e347ae367b3f..98222939e75d5dd1b3510b4dd9401af6501208b5 100755
--- a/indra/llrender/llrender.h
+++ b/indra/llrender/llrender.h
@@ -262,6 +262,14 @@ class LLRender
 	friend class LLTexUnit;
 public:
 
+	enum eTexIndex
+	{
+		DIFFUSE_MAP = 0,
+		NORMAL_MAP,
+		SPECULAR_MAP,
+		NUM_TEXTURE_CHANNELS,
+	};
+	
 	typedef enum {
 		TRIANGLES = 0,
 		TRIANGLE_STRIP,
diff --git a/indra/llrender/llrendertarget.cpp b/indra/llrender/llrendertarget.cpp
index 5fb4fc8e520b3b26bf549c62d4e8351c734eb9f4..6e22712b94f8158b3d099c627ba71337156f42b9 100755
--- a/indra/llrender/llrendertarget.cpp
+++ b/indra/llrender/llrendertarget.cpp
@@ -53,11 +53,19 @@ void check_framebuffer_status()
 bool LLRenderTarget::sUseFBO = false;
 U32 LLRenderTarget::sCurFBO = 0;
 
+
+extern S32 gGLViewport[4];
+
+U32 LLRenderTarget::sCurResX = 0;
+U32 LLRenderTarget::sCurResY = 0;
+
 LLRenderTarget::LLRenderTarget() :
 	mResX(0),
 	mResY(0),
 	mFBO(0),
 	mPreviousFBO(0),
+	mPreviousResX(0),
+	mPreviousResY(0),
 	mDepth(0),
 	mStencil(0),
 	mUseDepth(false),
@@ -390,13 +398,12 @@ void LLRenderTarget::bindTarget()
 {
 	if (mFBO)
 	{
-		mPreviousFBO = sCurFBO;
-
 		stop_glerror();
 		
+		mPreviousFBO = sCurFBO;
 		glBindFramebuffer(GL_FRAMEBUFFER, mFBO);
 		sCurFBO = mFBO;
-
+		
 		stop_glerror();
 		if (gGLManager.mHasDrawBuffers)
 		{ //setup multiple render targets
@@ -418,7 +425,12 @@ void LLRenderTarget::bindTarget()
 		stop_glerror();
 	}
 
+	mPreviousResX = sCurResX;
+	mPreviousResY = sCurResY;
 	glViewport(0, 0, mResX, mResY);
+	sCurResX = mResX;
+	sCurResY = mResY;
+
 	sBoundTarget = this;
 }
 
@@ -489,6 +501,20 @@ void LLRenderTarget::flush(bool fetch_depth)
 		stop_glerror();
 		glBindFramebuffer(GL_FRAMEBUFFER, mPreviousFBO);
 		sCurFBO = mPreviousFBO;
+
+		if (mPreviousFBO)
+		{
+			glViewport(0, 0, mPreviousResX, mPreviousResY);
+			sCurResX = mPreviousResX;
+			sCurResY = mPreviousResY;
+		}
+		else
+		{
+			glViewport(gGLViewport[0],gGLViewport[1],gGLViewport[2],gGLViewport[3]);
+			sCurResX = gGLViewport[2];
+			sCurResY = gGLViewport[3];
+		}
+						
 		stop_glerror();
 	}
 }
diff --git a/indra/llrender/llrendertarget.h b/indra/llrender/llrendertarget.h
index 765a727b5b9ea358403491e9ac6bebec8e185fc3..66a9874a6b20ddd5ba41964b07e436a8c8e3f3ca 100755
--- a/indra/llrender/llrendertarget.h
+++ b/indra/llrender/llrendertarget.h
@@ -63,6 +63,9 @@ class LLRenderTarget
 	static bool sUseFBO; 
 	static U32 sBytesAllocated;
 	static U32 sCurFBO;
+	static U32 sCurResX;
+	static U32 sCurResY;
+
 
 	LLRenderTarget();
 	~LLRenderTarget();
@@ -146,6 +149,9 @@ class LLRenderTarget
 	std::vector<U32> mInternalFormat;
 	U32 mFBO;
 	U32 mPreviousFBO;
+	U32 mPreviousResX;
+	U32 mPreviousResY;
+
 	U32 mDepth;
 	bool mStencil;
 	bool mUseDepth;
diff --git a/indra/llrender/llshadermgr.cpp b/indra/llrender/llshadermgr.cpp
index b6a9a6b653a28c37b69929713fe65046913815c5..fea4ee28198faa0ce693ca842fd3b66507daaac0 100755
--- a/indra/llrender/llshadermgr.cpp
+++ b/indra/llrender/llshadermgr.cpp
@@ -521,7 +521,7 @@ void LLShaderMgr::dumpObjectLog(GLhandleARB ret, BOOL warns)
 	}
  }
 
-GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, S32 texture_index_channels)
+GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, boost::unordered_map<std::string, std::string>* defines, S32 texture_index_channels)
 {
 	GLenum error = GL_NO_ERROR;
 	if (gDebugGL)
@@ -650,13 +650,15 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 			text[count++] = strdup("#define shadow2DRect(a,b) vec2(texture(a,b))\n");
 		}
 	}
-
-	//copy preprocessor definitions into buffer
-	for (std::map<std::string,std::string>::iterator iter = mDefinitions.begin(); iter != mDefinitions.end(); ++iter)
+	
+	if (defines)
+	{
+		for (boost::unordered_map<std::string,std::string>::iterator iter = defines->begin(); iter != defines->end(); ++iter)
 	{
 		std::string define = "#define " + iter->first + " " + iter->second + "\n";
 		text[count++] = (GLcharARB *) strdup(define.c_str());
 	}
+	}
 
 	if (texture_index_channels > 0 && type == GL_FRAGMENT_SHADER_ARB)
 	{
@@ -693,6 +695,8 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 		}
 		*/
 
+		text[count++] = strdup("#define HAS_DIFFUSE_LOOKUP 1\n");
+
 		//uniform declartion
 		for (S32 i = 0; i < texture_index_channels; ++i)
 		{
@@ -750,6 +754,10 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 			llerrs << "Indexed texture rendering requires GLSL 1.30 or later." << llendl;
 		}
 	}
+	else
+	{
+		text[count++] = strdup("#define HAS_DIFFUSE_LOOKUP 0\n");
+	}
 
 	//copy file into memory
 	while( fgets((char *)buff, 1024, file) != NULL && count < LL_ARRAY_SIZE(text) ) 
@@ -806,7 +814,6 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 				//an error occured, print log
 				LL_WARNS("ShaderLoading") << "GLSL Compilation Error: (" << error << ") in " << filename << LL_ENDL;
 				dumpObjectLog(ret);
-
 #if LL_WINDOWS
 				std::stringstream ostr;
 				//dump shader source for debugging
@@ -824,8 +831,20 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 				}
 
 				LL_WARNS("ShaderLoading") << "\n" << ostr.str() << llendl;
-#endif // LL_WINDOWS
-
+#else
+				std::string str;
+				
+				for (GLuint i = 0; i < count; i++) {
+					str.append(text[i]);
+					
+					if (i % 128 == 0)
+					{
+						LL_WARNS("ShaderLoading") << str << llendl;
+						str = "";
+					}
+				}
+#endif
+				
 				ret = 0;
 			}
 		}
@@ -854,7 +873,7 @@ GLhandleARB LLShaderMgr::loadShaderFile(const std::string& filename, S32 & shade
 		if (shader_level > 1)
 		{
 			shader_level--;
-			return loadShaderFile(filename,shader_level,type,texture_index_channels);
+			return loadShaderFile(filename,shader_level,type, defines, texture_index_channels);
 		}
 		LL_WARNS("ShaderLoading") << "Failed to load " << filename << LL_ENDL;	
 	}
@@ -958,7 +977,7 @@ void LLShaderMgr::initAttribsAndUniforms()
 	mReservedAttribs.push_back("texcoord3");
 	mReservedAttribs.push_back("diffuse_color");
 	mReservedAttribs.push_back("emissive");
-	mReservedAttribs.push_back("binormal");
+	mReservedAttribs.push_back("tangent");
 	mReservedAttribs.push_back("weight");
 	mReservedAttribs.push_back("weight4");
 	mReservedAttribs.push_back("clothing");
@@ -1055,6 +1074,7 @@ void LLShaderMgr::initAttribsAndUniforms()
 
 
 	mReservedUniforms.push_back("minimum_alpha");
+	mReservedUniforms.push_back("emissive_brightness");
 
 	mReservedUniforms.push_back("shadow_matrix");
 	mReservedUniforms.push_back("env_mat");
@@ -1115,6 +1135,12 @@ void LLShaderMgr::initAttribsAndUniforms()
 	mReservedUniforms.push_back("lightMap");
 	mReservedUniforms.push_back("bloomMap");
 	mReservedUniforms.push_back("projectionMap");
+	
+	mReservedUniforms.push_back("global_gamma");
+	mReservedUniforms.push_back("texture_gamma");
+	
+	mReservedUniforms.push_back("specular_color");
+	mReservedUniforms.push_back("env_intensity");
 
 	llassert(mReservedUniforms.size() == END_RESERVED_UNIFORMS);
 
diff --git a/indra/llrender/llshadermgr.h b/indra/llrender/llshadermgr.h
index 7a16b7c20fd6585b042476ce5d29173af3ab3567..c049e935b83e8a50f813cf201c44639aeaa82a1a 100755
--- a/indra/llrender/llshadermgr.h
+++ b/indra/llrender/llshadermgr.h
@@ -109,6 +109,7 @@ class LLShaderMgr
 		GLOW_DELTA,
 
 		MINIMUM_ALPHA,
+		EMISSIVE_BRIGHTNESS,
 
 		DEFERRED_SHADOW_MATRIX,
 		DEFERRED_ENV_MAT,
@@ -164,6 +165,13 @@ class LLShaderMgr
 		DEFERRED_LIGHT,
 		DEFERRED_BLOOM,
 		DEFERRED_PROJECTION,
+		
+		GLOBAL_GAMMA,
+		TEXTURE_GAMMA,
+		
+		SPECULAR_COLOR,
+		ENVIRONMENT_INTENSITY,
+		
 		END_RESERVED_UNIFORMS
 	} eGLSLReservedUniforms;
 
@@ -176,7 +184,7 @@ class LLShaderMgr
 	void dumpObjectLog(GLhandleARB ret, BOOL warns = TRUE);
 	BOOL	linkProgramObject(GLhandleARB obj, BOOL suppress_errors = FALSE);
 	BOOL	validateProgramObject(GLhandleARB obj);
-	GLhandleARB loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, S32 texture_index_channels = -1);
+	GLhandleARB loadShaderFile(const std::string& filename, S32 & shader_level, GLenum type, boost::unordered_map<std::string, std::string>* defines = NULL, S32 texture_index_channels = -1);
 
 	// Implemented in the application to actually point to the shader directory.
 	virtual std::string getShaderDirPrefix(void) = 0; // Pure Virtual
diff --git a/indra/llrender/llvertexbuffer.cpp b/indra/llrender/llvertexbuffer.cpp
index 4909b43e8aa126be2975054d6eec33fc08c8d4f0..01541026b100d7967d8f332cce47054d0cff7753 100755
--- a/indra/llrender/llvertexbuffer.cpp
+++ b/indra/llrender/llvertexbuffer.cpp
@@ -342,13 +342,32 @@ S32 LLVertexBuffer::sTypeSize[LLVertexBuffer::TYPE_MAX] =
 	sizeof(LLVector2), // TYPE_TEXCOORD3,
 	sizeof(LLColor4U), // TYPE_COLOR,
 	sizeof(LLColor4U), // TYPE_EMISSIVE, only alpha is used currently
-	sizeof(LLVector4), // TYPE_BINORMAL,
+	sizeof(LLVector4), // TYPE_TANGENT,
 	sizeof(F32),	   // TYPE_WEIGHT,
 	sizeof(LLVector4), // TYPE_WEIGHT4,
 	sizeof(LLVector4), // TYPE_CLOTHWEIGHT,
 	sizeof(LLVector4), // TYPE_TEXTURE_INDEX (actually exists as position.w), no extra data, but stride is 16 bytes
 };
 
+static std::string vb_type_name[] =
+{
+	"TYPE_VERTEX",
+	"TYPE_NORMAL",
+	"TYPE_TEXCOORD0",
+	"TYPE_TEXCOORD1",
+	"TYPE_TEXCOORD2",
+	"TYPE_TEXCOORD3",
+	"TYPE_COLOR",
+	"TYPE_EMISSIVE",
+	"TYPE_TANGENT",
+	"TYPE_WEIGHT",
+	"TYPE_WEIGHT4",
+	"TYPE_CLOTHWEIGHT",
+	"TYPE_TEXTURE_INDEX",
+	"TYPE_MAX",
+	"TYPE_INDEX",	
+};
+
 U32 LLVertexBuffer::sGLMode[LLRender::NUM_MODES] = 
 {
 	GL_TRIANGLES,
@@ -523,16 +542,16 @@ void LLVertexBuffer::setupClientArrays(U32 data_mask)
 				}
 			}
 
-			if (sLastMask & MAP_BINORMAL)
+			if (sLastMask & MAP_TANGENT)
 			{
-				if (!(data_mask & MAP_BINORMAL))
+				if (!(data_mask & MAP_TANGENT))
 				{
 					glClientActiveTextureARB(GL_TEXTURE2_ARB);
 					glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 					glClientActiveTextureARB(GL_TEXTURE0_ARB);
 				}
 			}
-			else if (data_mask & MAP_BINORMAL)
+			else if (data_mask & MAP_TANGENT)
 			{
 				glClientActiveTextureARB(GL_TEXTURE2_ARB);
 				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
@@ -593,8 +612,9 @@ void LLVertexBuffer::drawArrays(U32 mode, const std::vector<LLVector3>& pos, con
 		glVertexPointer(3, GL_FLOAT, 0, pos[0].mV);
 		glNormalPointer(GL_FLOAT, 0, norm[0].mV);
 	}
-
+	LLGLSLShader::startProfile();
 	glDrawArrays(sGLMode[mode], 0, count);
+	LLGLSLShader::stopProfile(count, mode);
 }
 
 //static
@@ -631,7 +651,9 @@ void LLVertexBuffer::drawElements(U32 mode, const LLVector4a* pos, const LLVecto
 		glVertexPointer(3, GL_FLOAT, 16, pos);
 	}
 
+	LLGLSLShader::startProfile();
 	glDrawElements(sGLMode[mode], num_indices, GL_UNSIGNED_SHORT, indicesp);
+	LLGLSLShader::stopProfile(num_indices, mode);
 }
 
 void LLVertexBuffer::validateRange(U32 start, U32 end, U32 count, U32 indices_offset) const
@@ -731,9 +753,14 @@ 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, 
 		idx);
+	LLGLSLShader::stopProfile(count, mode);
 	stop_glerror();
+
+	
+
 	placeFence();
 }
 
@@ -777,8 +804,10 @@ void LLVertexBuffer::draw(U32 mode, U32 count, U32 indices_offset) const
 	}
 
 	stop_glerror();
+	LLGLSLShader::startProfile();
 	glDrawElements(sGLMode[mode], count, GL_UNSIGNED_SHORT,
 		((U16*) getIndicesPointer()) + indices_offset);
+	LLGLSLShader::stopProfile(count, mode);
 	stop_glerror();
 	placeFence();
 }
@@ -820,9 +849,12 @@ void LLVertexBuffer::drawArrays(U32 mode, U32 first, U32 count) const
 
 	{
 		LLFastTimer t2(FTM_GL_DRAW_ARRAYS);
-		stop_glerror();
-		glDrawArrays(sGLMode[mode], first, count);
-	}
+	stop_glerror();
+	LLGLSLShader::startProfile();
+	glDrawArrays(sGLMode[mode], first, count);
+	LLGLSLShader::stopProfile(count, mode);
+        }
+
 	stop_glerror();
 	placeFence();
 }
@@ -1322,7 +1354,7 @@ void LLVertexBuffer::setupVertexArray()
 		2, //TYPE_TEXCOORD3,
 		4, //TYPE_COLOR,
 		4, //TYPE_EMISSIVE,
-		3, //TYPE_BINORMAL,
+		4, //TYPE_TANGENT,
 		1, //TYPE_WEIGHT,
 		4, //TYPE_WEIGHT4,
 		4, //TYPE_CLOTHWEIGHT,
@@ -1339,7 +1371,7 @@ void LLVertexBuffer::setupVertexArray()
 		GL_FLOAT, //TYPE_TEXCOORD3,
 		GL_UNSIGNED_BYTE, //TYPE_COLOR,
 		GL_UNSIGNED_BYTE, //TYPE_EMISSIVE,
-		GL_FLOAT,   //TYPE_BINORMAL,
+		GL_FLOAT,   //TYPE_TANGENT,
 		GL_FLOAT, //TYPE_WEIGHT,
 		GL_FLOAT, //TYPE_WEIGHT4,
 		GL_FLOAT, //TYPE_CLOTHWEIGHT,
@@ -1356,7 +1388,7 @@ void LLVertexBuffer::setupVertexArray()
 		false, //TYPE_TEXCOORD3,
 		false, //TYPE_COLOR,
 		false, //TYPE_EMISSIVE,
-		false, //TYPE_BINORMAL,
+		false, //TYPE_TANGENT,
 		false, //TYPE_WEIGHT,
 		false, //TYPE_WEIGHT4,
 		false, //TYPE_CLOTHWEIGHT,
@@ -1373,7 +1405,7 @@ void LLVertexBuffer::setupVertexArray()
 		GL_FALSE, //TYPE_TEXCOORD3,
 		GL_TRUE, //TYPE_COLOR,
 		GL_TRUE, //TYPE_EMISSIVE,
-		GL_FALSE,   //TYPE_BINORMAL,
+		GL_FALSE,   //TYPE_TANGENT,
 		GL_FALSE, //TYPE_WEIGHT,
 		GL_FALSE, //TYPE_WEIGHT4,
 		GL_FALSE, //TYPE_CLOTHWEIGHT,
@@ -2038,14 +2070,21 @@ bool LLVertexBuffer::getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 inde
 {
 	return VertexBufferStrider<LLVector2,TYPE_TEXCOORD1>::get(*this, strider, index, count, map_range);
 }
-
+bool LLVertexBuffer::getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index, S32 count, bool map_range)
+{
+	return VertexBufferStrider<LLVector2,TYPE_TEXCOORD2>::get(*this, strider, index, count, map_range);
+}
 bool LLVertexBuffer::getNormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
 {
 	return VertexBufferStrider<LLVector3,TYPE_NORMAL>::get(*this, strider, index, count, map_range);
 }
-bool LLVertexBuffer::getBinormalStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
+bool LLVertexBuffer::getTangentStrider(LLStrider<LLVector3>& strider, S32 index, S32 count, bool map_range)
 {
-	return VertexBufferStrider<LLVector3,TYPE_BINORMAL>::get(*this, strider, index, count, map_range);
+	return VertexBufferStrider<LLVector3,TYPE_TANGENT>::get(*this, strider, index, count, map_range);
+}
+bool LLVertexBuffer::getTangentStrider(LLStrider<LLVector4a>& strider, S32 index, S32 count, bool map_range)
+{
+	return VertexBufferStrider<LLVector4a,TYPE_TANGENT>::get(*this, strider, index, count, map_range);
 }
 bool LLVertexBuffer::getColorStrider(LLStrider<LLColor4U>& strider, S32 index, S32 count, bool map_range)
 {
@@ -2200,7 +2239,7 @@ void LLVertexBuffer::setBuffer(U32 data_mask)
 
 			if ((data_mask & required_mask) != required_mask)
 			{
-				llerrs << "Shader consumption mismatches data provision." << llendl;
+				llwarns << "Shader consumption mismatches data provision." << llendl;
 			}
 		}
 	}
@@ -2318,6 +2357,14 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
 
 	if (gDebugGL && ((data_mask & mTypeMask) != data_mask))
 	{
+		for (U32 i = 0; i < LLVertexBuffer::TYPE_MAX; ++i)
+		{
+			U32 mask = 1 << i;
+			if (mask & data_mask && !(mask & mTypeMask))
+			{ //bit set in data_mask, but not set in mTypeMask
+				llwarns << "Missing required component " << vb_type_name[i] << llendl;
+			}
+		}
 		llerrs << "LLVertexBuffer::setupVertexBuffer missing required components for supplied data mask." << llendl;
 	}
 
@@ -2347,11 +2394,11 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
 			void* ptr = (void*)(base + mOffsets[TYPE_TEXCOORD1]);
 			glVertexAttribPointerARB(loc,2,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], ptr);
 		}
-		if (data_mask & MAP_BINORMAL)
+		if (data_mask & MAP_TANGENT)
 		{
-			S32 loc = TYPE_BINORMAL;
-			void* ptr = (void*)(base + mOffsets[TYPE_BINORMAL]);
-			glVertexAttribPointerARB(loc, 3,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], ptr);
+			S32 loc = TYPE_TANGENT;
+			void* ptr = (void*)(base + mOffsets[TYPE_TANGENT]);
+			glVertexAttribPointerARB(loc, 4,GL_FLOAT, GL_FALSE, LLVertexBuffer::sTypeSize[TYPE_TANGENT], ptr);
 		}
 		if (data_mask & MAP_TEXCOORD0)
 		{
@@ -2429,10 +2476,10 @@ void LLVertexBuffer::setupVertexBuffer(U32 data_mask)
 			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
 			glClientActiveTextureARB(GL_TEXTURE0_ARB);
 		}
-		if (data_mask & MAP_BINORMAL)
+		if (data_mask & MAP_TANGENT)
 		{
 			glClientActiveTextureARB(GL_TEXTURE2_ARB);
-			glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
+			glTexCoordPointer(4,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TANGENT], (void*)(base + mOffsets[TYPE_TANGENT]));
 			glClientActiveTextureARB(GL_TEXTURE0_ARB);
 		}
 		if (data_mask & MAP_TEXCOORD0)
diff --git a/indra/llrender/llvertexbuffer.h b/indra/llrender/llvertexbuffer.h
index 11fa4ab6a0da3b7862298801072572cf9dd0b3dd..04806c1d8c20eff04aaa6c241507ff6ec27ef26d 100755
--- a/indra/llrender/llvertexbuffer.h
+++ b/indra/llrender/llvertexbuffer.h
@@ -174,7 +174,7 @@ class LLVertexBuffer : public LLRefCount
 		TYPE_TEXCOORD3,
 		TYPE_COLOR,
 		TYPE_EMISSIVE,
-		TYPE_BINORMAL,
+		TYPE_TANGENT,
 		TYPE_WEIGHT,
 		TYPE_WEIGHT4,
 		TYPE_CLOTHWEIGHT,
@@ -192,7 +192,7 @@ class LLVertexBuffer : public LLRefCount
 		MAP_COLOR = (1<<TYPE_COLOR),
 		MAP_EMISSIVE = (1<<TYPE_EMISSIVE),
 		// These use VertexAttribPointer and should possibly be made generic
-		MAP_BINORMAL = (1<<TYPE_BINORMAL),
+		MAP_TANGENT = (1<<TYPE_TANGENT),
 		MAP_WEIGHT = (1<<TYPE_WEIGHT),
 		MAP_WEIGHT4 = (1<<TYPE_WEIGHT4),
 		MAP_CLOTHWEIGHT = (1<<TYPE_CLOTHWEIGHT),
@@ -250,8 +250,10 @@ class LLVertexBuffer : public LLRefCount
 	bool getIndexStrider(LLStrider<U16>& strider, S32 index=0, S32 count = -1, bool map_range = false);
 	bool getTexCoord0Strider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
 	bool getTexCoord1Strider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
+	bool getTexCoord2Strider(LLStrider<LLVector2>& strider, S32 index=0, S32 count = -1, bool map_range = false);
 	bool getNormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
-	bool getBinormalStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
+	bool getTangentStrider(LLStrider<LLVector3>& strider, S32 index=0, S32 count = -1, bool map_range = false);
+	bool getTangentStrider(LLStrider<LLVector4a>& strider, S32 index=0, S32 count = -1, bool map_range = false);
 	bool getColorStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
 	bool getTextureIndexStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
 	bool getEmissiveStrider(LLStrider<LLColor4U>& strider, S32 index=0, S32 count = -1, bool map_range = false);
diff --git a/indra/llui/lllocalcliprect.cpp b/indra/llui/lllocalcliprect.cpp
index 0620e0f52d972af82466c07e3fea403801a930ab..f3a526faeb33ca0aee3f64bdb2ae7a656795d640 100755
--- a/indra/llui/lllocalcliprect.cpp
+++ b/indra/llui/lllocalcliprect.cpp
@@ -33,7 +33,7 @@
 
 
 LLScreenClipRect::LLScreenClipRect(const LLRect& rect, BOOL enabled)
-	:	mScissorState(GL_SCISSOR_TEST),
+:	mScissorState(GL_SCISSOR_TEST),
 	mEnabled(enabled)
 {
 	if (mEnabled)
@@ -100,10 +100,10 @@ void LLScreenClipRect::updateScissorRegion()
 // LLLocalClipRect
 //---------------------------------------------------------------------------
 LLLocalClipRect::LLLocalClipRect(const LLRect& rect, BOOL enabled /* = TRUE */)
-	:	LLScreenClipRect(LLRect(rect.mLeft + LLFontGL::sCurOrigin.mX, 
-	rect.mTop + LLFontGL::sCurOrigin.mY, 
-	rect.mRight + LLFontGL::sCurOrigin.mX, 
-	rect.mBottom + LLFontGL::sCurOrigin.mY), enabled)
+:	LLScreenClipRect(LLRect(rect.mLeft + LLFontGL::sCurOrigin.mX, 
+					rect.mTop + LLFontGL::sCurOrigin.mY, 
+					rect.mRight + LLFontGL::sCurOrigin.mX, 
+					rect.mBottom + LLFontGL::sCurOrigin.mY), enabled)
 {}
 
 LLLocalClipRect::~LLLocalClipRect()
diff --git a/indra/llui/llxuiparser.cpp b/indra/llui/llxuiparser.cpp
index 3ad5ad7d425dfeda1f2ecb9d2bc9c00dfbddb0ab..6322da91235d90a3084371f61d8d03503828b2cd 100755
--- a/indra/llui/llxuiparser.cpp
+++ b/indra/llui/llxuiparser.cpp
@@ -1309,10 +1309,8 @@ bool LLXUIParser::writeSDValue(Parser& parser, const void* val_ptr, name_stack_t
 void LLXUIParser::parserWarning(const std::string& message)
 {
 #ifdef LL_WINDOWS
-	// use Visual Studo friendly formatting of output message for easy access to originating xml
-	llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", mCurFileName.c_str(), mCurReadNode->getLineNumber(), message.c_str()).c_str());
-	utf16str += '\n';
-	OutputDebugString(utf16str.c_str());
+	// use Visual Studio friendly formatting of output message for easy access to originating xml
+	LL_WINDOWS_OUTPUT_DEBUG(llformat("%s(%d):\t%s", mCurFileName.c_str(), mCurReadNode->getLineNumber(), message.c_str()));
 #else
 	Parser::parserWarning(message);
 #endif
@@ -1321,9 +1319,8 @@ void LLXUIParser::parserWarning(const std::string& message)
 void LLXUIParser::parserError(const std::string& message)
 {
 #ifdef LL_WINDOWS
-	llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", mCurFileName.c_str(), mCurReadNode->getLineNumber(), message.c_str()).c_str());
-	utf16str += '\n';
-	OutputDebugString(utf16str.c_str());
+        // use Visual Studio friendly formatting of output message for easy access to originating xml
+	LL_WINDOWS_OUTPUT_DEBUG(llformat("%s(%d):\t%s", mCurFileName.c_str(), mCurReadNode->getLineNumber(), message.c_str()));
 #else
 	Parser::parserError(message);
 #endif
@@ -1640,10 +1637,8 @@ bool LLSimpleXUIParser::processText()
 void LLSimpleXUIParser::parserWarning(const std::string& message)
 {
 #ifdef LL_WINDOWS
-	// use Visual Studo friendly formatting of output message for easy access to originating xml
-	llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", mCurFileName.c_str(), LINE_NUMBER_HERE, message.c_str()).c_str());
-	utf16str += '\n';
-	OutputDebugString(utf16str.c_str());
+	// use Visual Studio friendly formatting of output message for easy access to originating xml
+	LL_WINDOWS_OUTPUT_DEBUG(llformat("%s(%d):\t%s", mCurFileName.c_str(), LINE_NUMBER_HERE, message.c_str()));
 #else
 	Parser::parserWarning(message);
 #endif
@@ -1652,9 +1647,8 @@ void LLSimpleXUIParser::parserWarning(const std::string& message)
 void LLSimpleXUIParser::parserError(const std::string& message)
 {
 #ifdef LL_WINDOWS
-	llutf16string utf16str = utf8str_to_utf16str(llformat("%s(%d):\t%s", mCurFileName.c_str(), LINE_NUMBER_HERE, message.c_str()).c_str());
-	utf16str += '\n';
-	OutputDebugString(utf16str.c_str());
+        // use Visual Studio friendly formatting of output message for easy access to originating xml
+	LL_WINDOWS_OUTPUT_DEBUG(llformat("%s(%d):\t%s", mCurFileName.c_str(), LINE_NUMBER_HERE, message.c_str()));
 #else
 	Parser::parserError(message);
 #endif
diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp
index 462d1cce0662555a7057dc54ba8c862ae3089498..618409595767c965fc6c02052a521767197bf7e5 100755
--- a/indra/llvfs/lldir_win32.cpp
+++ b/indra/llvfs/lldir_win32.cpp
@@ -131,7 +131,7 @@ LLDir_Win32::LLDir_Win32()
 		mAppRODataDir = mExecutableDir;
 	}
 
-	llinfos << "mAppRODataDir = " << mAppRODataDir << llendl;
+//	llinfos << "mAppRODataDir = " << mAppRODataDir << llendl;
 
 	mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins";
 
diff --git a/indra/llvfs/llvfile.cpp b/indra/llvfs/llvfile.cpp
index 03d2cc25e335bcd9eb75ce6c15aaf1a8a663d45f..306d7d8ec706dadbe0533abd5207c118e1261916 100755
--- a/indra/llvfs/llvfile.cpp
+++ b/indra/llvfs/llvfile.cpp
@@ -135,7 +135,7 @@ U8* LLVFile::readFile(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, S
 		data = NULL;
 	}
 	else
-	{		
+	{
 		data = (U8*) ll_aligned_malloc_16(file_size);
 		file.read(data, file_size);	/* Flawfinder: ignore */ 
 		
diff --git a/indra/llwindow/CMakeLists.txt b/indra/llwindow/CMakeLists.txt
index ad010164eb15977f259dc2b8436f3fb1d901ba45..4c6e7061192005be34154266197d50787472d234 100755
--- a/indra/llwindow/CMakeLists.txt
+++ b/indra/llwindow/CMakeLists.txt
@@ -165,7 +165,7 @@ if (BUILD_HEADLESS)
   set(llwindowheadless_HEADER_FILES
        llwindowmesaheadless.h
        llmousehandler.h
-       )
+    )
   add_library (llwindowheadless
     ${llwindow_SOURCE_FILES}
     ${llwindowheadless_SOURCE_FILES}
@@ -180,12 +180,12 @@ if (llwindow_HEADER_FILES)
   list(APPEND llwindow_SOURCE_FILES ${llwindow_HEADER_FILES})
 endif (llwindow_HEADER_FILES)
 
-list(APPEND viewer_SOURCE_FILES ${viewer_HEADER_FILES})
+  list(APPEND viewer_SOURCE_FILES ${viewer_HEADER_FILES})
 
-add_library (llwindow
-  ${llwindow_SOURCE_FILES}
-  ${viewer_SOURCE_FILES}
-  )
+  add_library (llwindow
+    ${llwindow_SOURCE_FILES}
+    ${viewer_SOURCE_FILES}
+    )
 
 if (SDL_FOUND)
   set_property(TARGET llwindow
@@ -193,5 +193,5 @@ if (SDL_FOUND)
     )
 endif (SDL_FOUND)
 
-target_link_libraries (llwindow ${llwindow_LINK_LIBRARIES})
+  target_link_libraries (llwindow ${llwindow_LINK_LIBRARIES})
 
diff --git a/indra/llxml/CMakeLists.txt b/indra/llxml/CMakeLists.txt
index cf96f26a77a2c17e7b464f5591f15e46ad796770..17400a203e8485bb46b62f4011c60e1fe93fad36 100755
--- a/indra/llxml/CMakeLists.txt
+++ b/indra/llxml/CMakeLists.txt
@@ -42,7 +42,7 @@ list(APPEND llxml_SOURCE_FILES ${llxml_HEADER_FILES})
 add_library (llxml ${llxml_SOURCE_FILES})
 # Libraries on which this library depends, needed for Linux builds
 # Sort by high-level to low-level
-target_link_libraries(llxml
+target_link_libraries( llxml
     ${LLVFS_LIBRARIES}
     ${LLMATH_LIBRARIES}
     ${LLCOMMON_LIBRARIES}
diff --git a/indra/lscript/lscript_compile/indra.l b/indra/lscript/lscript_compile/indra.l
index b2c49083cb267398b1c32ce636317b40504b84a8..1bb38bbf655f5c3313db95b81055e6cb52b2a2eb 100755
--- a/indra/lscript/lscript_compile/indra.l
+++ b/indra/lscript/lscript_compile/indra.l
@@ -79,11 +79,9 @@ void parse_string();
 #define yyfree indra_free
 
 
-#if defined(__cplusplus)
-extern "C" { int yylex( void ); }
-extern "C" { int yyparse( void ); }
-extern "C" { int yyerror(const char *fmt, ...); }
-#endif
+int yylex( void );
+int yyparse( void );
+int yyerror(const char *fmt, ...);
 
 %}
 
diff --git a/indra/lscript/lscript_compile/indra.y b/indra/lscript/lscript_compile/indra.y
index e4b10ffdd9da7d96dd1a75217a65de0964056a72..a0a034d21c2251a9035825f72e2781c80ced719c 100755
--- a/indra/lscript/lscript_compile/indra.y
+++ b/indra/lscript/lscript_compile/indra.y
@@ -2,10 +2,6 @@
 	#include "linden_common.h"
 	#include "lscript_tree.h"
 
-    #ifdef __cplusplus
-    extern "C" {
-    #endif
-
 	int yylex(void);
 	int yyparse( void );
 	int yyerror(const char *fmt, ...);
@@ -20,9 +16,6 @@
 	#pragma warning( disable : 4065 )	// warning: switch statement contains 'default' but no 'case' labels
 	#endif
 
-    #ifdef __cplusplus
-    }
-    #endif
 %}
 
 %union
diff --git a/indra/mac_crash_logger/CrashReporter.nib b/indra/mac_crash_logger/CrashReporter.nib
index a30d8d205cf76f486649b9f9eee9e8f4928a4b97..e9d9e059855078b54b9d1d3c382f7f241cab9e27 100755
Binary files a/indra/mac_crash_logger/CrashReporter.nib and b/indra/mac_crash_logger/CrashReporter.nib differ
diff --git a/indra/media_plugins/winmmshim/winmm_shim.cpp b/indra/media_plugins/winmmshim/winmm_shim.cpp
index 47a1e5c0187acf98e37cad50e763433170f8c27a..aac349bf57d526e3d6ef979a13d82d36385d3b36 100755
--- a/indra/media_plugins/winmmshim/winmm_shim.cpp
+++ b/indra/media_plugins/winmmshim/winmm_shim.cpp
@@ -56,7 +56,7 @@ void ll_winmm_shim_initialize(){
 		// grab winmm.dll from system path, where it should live
 		wsprintf(dll_path, "%s\\winmm.dll", system_path);
 		HMODULE winmm_handle = ::LoadLibrary(dll_path);
-		
+
 		if (winmm_handle != NULL)
 		{	// we have a dll, let's get out pointers!
 			initialized = true;
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 227644f14f08322388c7eed0a92e8dbc45426f4e..d06cee5ee638e13ae6384ba0e155fa3999a29977 100755
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -4,6 +4,7 @@ project(viewer)
 
 include(00-Common)
 include(Boost)
+include(BuildVersion)
 include(DBusGlib)
 include(DirectX)
 include(OpenSSL)
@@ -173,6 +174,7 @@ set(viewer_SOURCE_FILES
     lldrawpoolavatar.cpp
     lldrawpoolbump.cpp
     lldrawpoolground.cpp
+    lldrawpoolmaterials.cpp
     lldrawpoolsimple.cpp
     lldrawpoolsky.cpp
     lldrawpoolterrain.cpp
@@ -357,6 +359,7 @@ set(viewer_SOURCE_FILES
     llmaniptranslate.cpp
     llmarketplacefunctions.cpp
     llmarketplacenotifications.cpp
+    llmaterialmgr.cpp
     llmediactrl.cpp
     llmediadataclient.cpp
     llmenuoptionpathfindingrebakenavmesh.cpp
@@ -753,6 +756,7 @@ set(viewer_HEADER_FILES
     lldrawpoolalpha.h
     lldrawpoolavatar.h
     lldrawpoolbump.h
+    lldrawpoolmaterials.h
     lldrawpoolground.h
     lldrawpoolsimple.h
     lldrawpoolsky.h
@@ -937,6 +941,7 @@ set(viewer_HEADER_FILES
     llmaniptranslate.h
     llmarketplacefunctions.h
     llmarketplacenotifications.h
+    llmaterialmgr.h
     llmediactrl.h
     llmediadataclient.h
     llmenuoptionpathfindingrebakenavmesh.h
@@ -1563,7 +1568,7 @@ endif (WINDOWS)
 
 if (OPENAL)
   set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_OPENAL")
-endif (OPENAL)          
+endif (OPENAL)
 
 if (FMODEX)
   set(LLSTARTUP_COMPILE_FLAGS "${LLSTARTUP_COMPILE_FLAGS} -DLL_FMODEX")
@@ -1983,7 +1988,7 @@ if (DARWIN)
   configure_file(
      "${CMAKE_CURRENT_SOURCE_DIR}/Info-SecondLife.plist"
      "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}/${product}.app/Contents/Info.plist"
-               )
+    )
 
   add_custom_command(
     TARGET ${VIEWER_BINARY_NAME} POST_BUILD
@@ -2136,6 +2141,40 @@ if (LL_TESTS)
     LL_TEST_ADDITIONAL_LIBRARIES "${JSONCPP_LIBRARIES}"
   )
 
+  set_source_files_properties(
+    llviewerhelputil.cpp
+    PROPERTIES
+    LL_TEST_ADDITIONAL_LIBRARIES "${BOOST_SYSTEM_LIBRARY}"
+  )
+
+  set_source_files_properties(
+    llremoteparcelrequest.cpp
+    PROPERTIES
+    LL_TEST_ADDITIONAL_LIBRARIES "${BOOST_SYSTEM_LIBRARY}"
+  )
+
+  set_source_files_properties(
+    llworldmap.cpp
+    llworldmipmap.cpp
+    PROPERTIES
+    LL_TEST_ADDITIONAL_SOURCE_FILES 
+    tests/llviewertexture_stub.cpp
+    #llviewertexturelist.cpp
+    LL_TEST_ADDITIONAL_LIBRARIES "${BOOST_SYSTEM_LIBRARY}"
+  )
+
+  set_source_files_properties(
+    llmediadataclient.cpp
+    PROPERTIES
+    LL_TEST_ADDITIONAL_LIBRARIES "${LLPRIMITIVE_LIBRARIES}"
+  )
+
+  set_source_files_properties(
+    llagentaccess.cpp
+    PROPERTIES
+    LL_TEST_ADDITIONAL_LIBRARIES "${BOOST_SYSTEM_LIBRARY}"
+  )
+
   set_source_files_properties(
     lllogininstance.cpp
     PROPERTIES
diff --git a/indra/newview/VIEWER_VERSION.txt b/indra/newview/VIEWER_VERSION.txt
index 65afb3b88612378e83aadbe1135d71cc1e5e07e6..b72762837ea636398fece3c5651f664c2ee82ffb 100644
--- a/indra/newview/VIEWER_VERSION.txt
+++ b/indra/newview/VIEWER_VERSION.txt
@@ -1 +1 @@
-3.5.4
+3.6.2
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index f356cff9d89fd3cb1b610e5656189116a79b5f23..344079b640c7daac52dd476717171f42d6d601de 100755
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -2873,6 +2873,17 @@
       <key>Value</key>
       <integer>0</integer>
     </map>
+  <key>DefaultBlankNormalTexture</key>
+  <map>
+    <key>Comment</key>
+    <string>Texture used as 'Blank' in texture picker for normal maps. (UUID texture reference)</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>String</string>
+    <key>Value</key>
+    <string>5b53359e-59dd-d8a2-04c3-9e65134da47a</string>
+  </map>
 	<key>DefaultFemaleAvatar</key>
 	<map>
 	  <key>Comment</key>
@@ -2895,8 +2906,29 @@
 	  <key>Value</key>
 	  <string>Male Shape &amp; Outfit</string>
 	</map>
-
-    <key>DefaultObjectTexture</key>
+  <key>DefaultObjectNormalTexture</key>
+  <map>
+    <key>Comment</key>
+    <string>Texture used as 'Default' in texture picker for normal map. (UUID texture reference)</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>String</string>
+    <key>Value</key>
+    <string>85f28839-7a1c-b4e3-d71d-967792970a7b</string>
+  </map>
+  <key>DefaultObjectSpecularTexture</key>
+  <map>
+    <key>Comment</key>
+    <string>Texture used as 'Default' in texture picker for specular map. (UUID texture reference)</string>
+    <key>Persist</key>
+    <integer>1</integer>
+    <key>Type</key>
+    <string>String</string>
+    <key>Value</key>
+    <string>87e0e8f7-8729-1ea8-cfc9-8915773009db</string>
+  </map>
+  <key>DefaultObjectTexture</key>
     <map>
       <key>Comment</key>
       <string>Texture used as 'Default' in texture picker. (UUID texture reference)</string>
@@ -3347,17 +3379,6 @@
       <key>Value</key>
       <integer>1</integer>
     </map>
-    <key>EnableTextureAtlas</key>
-    <map>
-      <key>Comment</key>
-      <string>Whether to use texture atlas or not</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>0</integer>
-    </map>
     <key>EnableUIHints</key>
     <map>
       <key>Comment</key>
@@ -7711,7 +7732,7 @@
     <key>Type</key>
     <string>S32</string>
     <key>Value</key>
-    <integer>4</integer>
+    <integer>3</integer>
   </map>
 
   <key>OctreeAlphaDistanceFactor</key>
@@ -8440,7 +8461,7 @@
   <key>RenderSpotLightsInNondeferred</key>
   <map>
     <key>Comment</key>
-    <string>Whether to support projectors as spotlights when Lighting and Shadows is disabled</string>
+    <string>Whether to support projectors as spotlights when Advanced Lighting Model is disabled</string>
     <key>Persist</key>
     <integer>1</integer>
     <key>Type</key>
@@ -8483,7 +8504,6 @@
     <key>Value</key>
     <real>1.0</real>
   </map>
-
   <key>RenderDeferredTreeShadowBias</key>
   <map>
     <key>Comment</key>
@@ -8581,7 +8601,7 @@
     <key>Type</key>
     <string>U32</string>
     <key>Value</key>
-    <real>512</real>
+    <real>1024</real>
   </map>
 
   <key>RenderSpecularResY</key>
@@ -8593,7 +8613,7 @@
     <key>Type</key>
     <string>U32</string>
     <key>Value</key>
-    <real>128</real>
+    <real>256</real>
   </map>
 
   <key>RenderSpecularExponent</key>
@@ -8611,7 +8631,7 @@
   <key>RenderDeferred</key>
   <map>
     <key>Comment</key>
-    <string>Use deferred rendering pipeline.</string>
+    <string>Use deferred rendering pipeline (Advanced Lighting Model).</string>
     <key>Persist</key>
     <integer>1</integer>
     <key>Type</key>
@@ -8799,7 +8819,7 @@
     <key>RenderAutoMaskAlphaNonDeferred</key>
     <map>
       <key>Comment</key>
-      <string>Use alpha masks where appropriate, in the non-deferred (non-'Lighting and Shadows') graphics mode</string>
+      <string>Use alpha masks where appropriate when not using the Advanced Lighting Model</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -8810,7 +8830,7 @@
     <key>RenderAutoMaskAlphaDeferred</key>
     <map>
       <key>Comment</key>
-      <string>Use alpha masks where appropriate, in the deferred ('Lighting and Shadows') graphics mode</string>
+      <string>Use alpha masks where appropriate in the Advanced Lighting Model</string>
       <key>Persist</key>
       <integer>1</integer>
       <key>Type</key>
@@ -12461,17 +12481,6 @@
       <key>Value</key>
       <integer>3</integer>
     </map>
-    <key>UpdaterWillingToTest</key>
-    <map>
-      <key>Comment</key>
-      <string>Allow upgrades to release candidate viewers with new features and fixes.</string>
-      <key>Persist</key>
-      <integer>1</integer>
-      <key>Type</key>
-      <string>Boolean</string>
-      <key>Value</key>
-      <integer>1</integer>
-    </map>
     <key>UpdaterServiceCheckPeriod</key>
     <map>
       <key>Comment</key>
@@ -12855,7 +12864,6 @@
       <key>Type</key>
       <string>LLSD</string>
       <key>Value</key>
-      <string/>
     </map>
     <key>VFSOldSize</key>
     <map>
@@ -14524,5 +14532,16 @@
     <key>Value</key>
     <integer>7000</integer>
   </map>
+  <key>DisablePrecacheDelayAfterTeleporting</key>
+  <map>
+    <key>Comment</key>
+    <string>Disables the artificial delay in the viewer that precaches some incoming assets</string>
+    <key>Persist</key>
+    <integer>0</integer>
+    <key>Type</key>
+    <string>Boolean</string>
+    <key>Value</key>
+    <integer>0</integer>
+  </map>
 </map>
 </llsd>
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
index dd87ddb330edbfa39b2a079b1b57b603e2c43cbc..0899caa2af6e84884ce371daa0caba5f8f5a0db9 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaF.glsl
@@ -25,17 +25,33 @@
  
 #extension GL_ARB_texture_rectangle : enable
 
+#define INDEXED 1
+#define NON_INDEXED 2
+#define NON_INDEXED_NO_COLOR 3
+
 #ifdef DEFINE_GL_FRAGCOLOR
 out vec4 frag_color;
 #else
 #define frag_color gl_FragColor
 #endif
 
-uniform sampler2DRect depthMap;
+#if HAS_SHADOW
+uniform sampler2DShadow shadowMap0;
+uniform sampler2DShadow shadowMap1;
+uniform sampler2DShadow shadowMap2;
+uniform sampler2DShadow shadowMap3;
 
-vec4 diffuseLookup(vec2 texcoord);
+uniform vec2 shadow_res;
 
-uniform vec2 screen_res;
+uniform mat4 shadow_matrix[6];
+uniform vec4 shadow_clip;
+uniform float shadow_bias;
+
+#endif
+
+#ifdef USE_DIFFUSE_TEX
+uniform sampler2D diffuseMap;
+#endif
 
 vec3 atmosLighting(vec3 light);
 vec3 scaleSoftClip(vec3 light);
@@ -45,11 +61,80 @@ 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;
 
+#ifdef USE_VERTEX_COLOR
 VARYING vec4 vertex_color;
-VARYING vec2 vary_texcoord0;
+#endif
+
+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 calcDirectionalLight(vec3 n, vec3 l)
+{
+	float a = max(dot(n,l),0.0);
+	a = pow(a, 1.0/1.3);
+	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 = length(lv);
+	
+	float da = 0.0;
+
+	if (d > 0.0 && la > 0.0 && fa > 0.0)
+	{
+		//normalize light vector
+		lv = normalize(lv);
+	
+		//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;
+	
+
+		// 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);	
+}
+
+#if HAS_SHADOW
+float pcfShadow(sampler2DShadow shadowMap, vec4 stc)
+{
+	stc.xyz /= stc.w;
+	stc.z += shadow_bias;
+		
+	stc.x = floor(stc.x*shadow_res.x + fract(stc.y*shadow_res.y*12345))/shadow_res.x; // add some chaotic jitter to X sample pos according to Y to disguise the snapping going on here
+	
+	float cs = shadow2D(shadowMap, stc.xyz).x;
+	float shadow = cs;
+	
+    shadow += shadow2D(shadowMap, stc.xyz+vec3(2.0/shadow_res.x, 1.5/shadow_res.y, 0.0)).x;
+    shadow += shadow2D(shadowMap, stc.xyz+vec3(1.0/shadow_res.x, -1.5/shadow_res.y, 0.0)).x;
+    shadow += shadow2D(shadowMap, stc.xyz+vec3(-1.0/shadow_res.x, 1.5/shadow_res.y, 0.0)).x;
+    shadow += shadow2D(shadowMap, stc.xyz+vec3(-2.0/shadow_res.x, -1.5/shadow_res.y, 0.0)).x;
+                       
+    return shadow*0.2;
+}
+#endif
 
-uniform mat4 inv_proj;
 
 void main() 
 {
@@ -58,16 +143,123 @@ void main()
 	
 	vec4 pos = vec4(vary_position, 1.0);
 	
-	vec4 diff= diffuseLookup(vary_texcoord0.xy);
 
-	vec4 col = vec4(vary_ambient + vary_directional.rgb, vertex_color.a);
-	vec4 color = diff * col;
+#if HAS_SHADOW
+	float shadow = 0.0;
+	vec4 spos = pos;
+		
+	if (spos.z > -shadow_clip.w)
+	{	
+		vec4 lpos;
+		
+		vec4 near_split = shadow_clip*-0.75;
+		vec4 far_split = shadow_clip*-1.25;
+		vec4 transition_domain = near_split-far_split;
+		float weight = 0.0;
+
+		if (spos.z < near_split.z)
+		{
+			lpos = shadow_matrix[3]*spos;
+			
+			float w = 1.0;
+			w -= max(spos.z-far_split.z, 0.0)/transition_domain.z;
+			shadow += pcfShadow(shadowMap3, lpos)*w;
+			weight += w;
+			shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0);
+		}
+
+		if (spos.z < near_split.y && spos.z > far_split.z)
+		{
+			lpos = shadow_matrix[2]*spos;
+			
+			float w = 1.0;
+			w -= max(spos.z-far_split.y, 0.0)/transition_domain.y;
+			w -= max(near_split.z-spos.z, 0.0)/transition_domain.z;
+			shadow += pcfShadow(shadowMap2, lpos)*w;
+			weight += w;
+		}
+
+		if (spos.z < near_split.x && spos.z > far_split.y)
+		{
+			lpos = shadow_matrix[1]*spos;
+			
+			float w = 1.0;
+			w -= max(spos.z-far_split.x, 0.0)/transition_domain.x;
+			w -= max(near_split.y-spos.z, 0.0)/transition_domain.y;
+			shadow += pcfShadow(shadowMap1, lpos)*w;
+			weight += w;
+		}
+
+		if (spos.z > far_split.x)
+		{
+			lpos = shadow_matrix[0]*spos;
+							
+			float w = 1.0;
+			w -= max(near_split.x-spos.z, 0.0)/transition_domain.x;
+				
+			shadow += pcfShadow(shadowMap0, lpos)*w;
+			weight += w;
+		}
+		
+
+		shadow /= weight;
+	}
+	else
+	{
+		shadow = 1.0;
+	}
+#endif
+
+#ifdef USE_INDEXED_TEX
+	vec4 diff = diffuseLookup(vary_texcoord0.xy);
+#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 USE_VERTEX_COLOR
+	float vertex_color_alpha = vertex_color.a;	
+#else
+	float vertex_color_alpha = 1.0;
+#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);
+#else
+	vec4 col = vec4(vary_ambient + dlight, vertex_color_alpha);
+#endif
+
+	vec4 color = gamma_diff * col;
 	
 	color.rgb = atmosLighting(color.rgb);
 
 	color.rgb = scaleSoftClip(color.rgb);
 
-	color.rgb += diff.rgb * vary_pointlight_col.rgb;
+	color.rgb = pow(color.rgb, vec3(2.2));
+	col = 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);
+
+	LIGHT_LOOP(1)
+	LIGHT_LOOP(2)
+	LIGHT_LOOP(3)
+	LIGHT_LOOP(4)
+	LIGHT_LOOP(5)
+	LIGHT_LOOP(6)
+	LIGHT_LOOP(7)
+
+	color.rgb += diff.rgb * pow(vary_pointlight_col, vec3(2.2)) * col.rgb;
+
+	color.rgb = pow(color.rgb, vec3(1.0/2.2));
 
 	frag_color = color;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedF.glsl
index beb329018727a568f9ff25e6966a2e8cc1b2bb93..2ce44d599f1190064efc18ab75b78c8ae9d780d6 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaNonIndexedF.glsl
@@ -47,9 +47,51 @@ VARYING vec3 vary_position;
 VARYING vec3 vary_pointlight_col;
 VARYING vec2 vary_texcoord0;
 VARYING vec4 vertex_color;
+VARYING vec3 vary_norm;
 
 uniform mat4 inv_proj;
 
+uniform vec4 light_position[8];
+uniform vec3 light_direction[8];
+uniform vec3 light_attenuation[8]; 
+uniform vec3 light_diffuse[8];
+
+vec3 calcDirectionalLight(vec3 n, vec3 l)
+{
+        float a = pow(max(dot(n,l),0.0), 0.7);
+        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(pow(dot(n, lv), 0.7), 0.0);		
+	}
+
+	return vec3(da,da,da);	
+}
+
 vec4 getPosition(vec2 pos_screen)
 {
 	float depth = texture2DRect(depthMap, pos_screen.xy).a;
@@ -72,14 +114,33 @@ void main()
 	
 	vec4 diff= texture2D(diffuseMap,vary_texcoord0.xy);
 
-	vec4 col = vec4(vary_ambient + vary_directional.rgb, vertex_color.a);
+	vec3 n = vary_norm;
+	vec3 l = light_position[0].xyz;
+	vec3 dlight = calcDirectionalLight(n, l);
+	dlight = dlight * vary_directional.rgb * vary_pointlight_col;
+
+	vec4 col = vec4(vary_ambient + dlight, vertex_color.a);
 	vec4 color = diff * col;
 	
 	color.rgb = atmosLighting(color.rgb);
 
 	color.rgb = scaleSoftClip(color.rgb);
+	vec3 light_col = vec3(0,0,0);
+
+  #define LIGHT_LOOP(i) \
+	light_col += light_diffuse[i].rgb * calcPointLightOrSpotLight(pos.xyz, vary_norm, light_position[i], light_direction[i], light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z);
+
+	LIGHT_LOOP(1)
+	LIGHT_LOOP(2)
+	LIGHT_LOOP(3)
+	LIGHT_LOOP(4)
+	LIGHT_LOOP(5)
+	LIGHT_LOOP(6)
+	LIGHT_LOOP(7)
+
+	color.rgb += diff.rgb * vary_pointlight_col * light_col;
 
-	color.rgb += diff.rgb * vary_pointlight_col.rgb;
+	color.rgb = pow(color.rgb, vec3(1.0/2.2));
 
 	frag_color = color;
 	//frag_color = vec4(1,0,1,1);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaSkinnedV.glsl
index 5a0e8ff68490f5c6860f5e3df697c4da06829bfe..5f93986f1d240c38904756653e9d04874d243dce 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaSkinnedV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaSkinnedV.glsl
@@ -46,6 +46,7 @@ VARYING vec3 vary_pointlight_col;
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
+VARYING vec3 vary_norm;
 
 uniform float near_clip;
 
@@ -104,7 +105,7 @@ void main()
 	
 	norm = position.xyz + normal.xyz;
 	norm = normalize(( trans*vec4(norm, 1.0) ).xyz-pos.xyz);
-	
+	vary_norm = norm;
 	vec4 frag_pos = projection_matrix * pos;
 	gl_Position = frag_pos;
 	
@@ -112,27 +113,18 @@ void main()
 		
 	calcAtmospherics(pos.xyz);
 
+	//vec4 color = calcLighting(pos.xyz, norm, diffuse_color, vec4(0.));
 	vec4 col = vec4(0.0, 0.0, 0.0, diffuse_color.a);
-
-	// Collect normal lights
-	col.rgb += light_diffuse[2].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].y, light_attenuation[2].z);
-	col.rgb += light_diffuse[3].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].y, light_attenuation[3].z);
-	col.rgb += light_diffuse[4].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[4], light_direction[4], light_attenuation[4].x, light_attenuation[4].y, light_attenuation[4].z);
-	col.rgb += light_diffuse[5].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[5], light_direction[5], light_attenuation[5].x, light_attenuation[5].y, light_attenuation[5].z);
-	col.rgb += light_diffuse[6].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[6], light_direction[6], light_attenuation[6].x, light_attenuation[6].y, light_attenuation[6].z);
-	col.rgb += light_diffuse[7].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[7], light_direction[7], light_attenuation[7].x, light_attenuation[7].y, light_attenuation[7].z);
-
-	vary_pointlight_col = col.rgb*diffuse_color.rgb;
-
+	vary_pointlight_col = diffuse_color.rgb;
 	col.rgb = vec3(0,0,0);
 
 	// Add windlight lights
 	col.rgb = atmosAmbient(vec3(0.));
 	
 	vary_ambient = col.rgb*diffuse_color.rgb;
-	vary_directional = diffuse_color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, light_position[0].xyz), (1.0-diffuse_color.a)*(1.0-diffuse_color.a)));
+	vary_directional.rgb = atmosAffectDirectionalLight(1);
 	
-	col.rgb = min(col.rgb*diffuse_color.rgb, 1.0);
+	col.rgb = col.rgb*diffuse_color.rgb;
 	
 	vertex_color = col;
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
index cf38a2f4f7908a1afff98b720d5160721ae7240b..9d3ba564cdc4556f18e3ef4a3eed801b48032168 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/alphaV.glsl
@@ -23,22 +23,41 @@
  * $/LicenseInfo$
  */
 
+#define INDEXED 1
+#define NON_INDEXED 2
+#define NON_INDEXED_NO_COLOR 3
+
 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);
 
-float calcDirectionalLight(vec3 n, vec3 l);
-
 vec3 atmosAmbient(vec3 light);
 vec3 atmosAffectDirectionalLight(float lightIntensity);
 vec3 scaleDownLight(vec3 light);
@@ -50,26 +69,24 @@ 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];
 
-float calcDirectionalLight(vec3 n, vec3 l)
-{
-        float a = max(dot(n,l),0.0);
-        return a;
-}
+uniform vec3 sun_dir;
 
-float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight)
+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;
@@ -96,53 +113,110 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa
 		da *= max(dot(n, lv), 0.0);		
 	}
 
-	return da;	
+	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);
-	passTextureIndex();
-	vec4 pos = (modelview_matrix * vert);
+	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
 	
-	vec3 norm = normalize(normal_matrix * normal);
-	
-	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;
-		
+	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;
 
-	// Collect normal lights
-	col.rgb += light_diffuse[2].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].y, light_attenuation[2].z);
-	col.rgb += light_diffuse[3].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].y, light_attenuation[3].z);
-	col.rgb += light_diffuse[4].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[4], light_direction[4], light_attenuation[4].x, light_attenuation[4].y, light_attenuation[4].z);
-	col.rgb += light_diffuse[5].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[5], light_direction[5], light_attenuation[5].x, light_attenuation[5].y, light_attenuation[5].z);
-	col.rgb += light_diffuse[6].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[6], light_direction[6], light_attenuation[6].x, light_attenuation[6].y, light_attenuation[6].z);
-	col.rgb += light_diffuse[7].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[7], light_direction[7], light_attenuation[7].x, light_attenuation[7].y, light_attenuation[7].z);
 	
-	vary_pointlight_col = col.rgb*diffuse_color.rgb;
 	col.rgb = vec3(0,0,0);
 
 	// Add windlight lights
-	col.rgb = atmosAmbient(vec3(0.));
+	col.rgb = atmosAmbient(col.rgb);
 	
-	vary_ambient = col.rgb*diffuse_color.rgb;
-	vary_directional.rgb = diffuse_color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, light_position[0].xyz), (1.0-diffuse_color.a)*(1.0-diffuse_color.a)));
+	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*diffuse_color.rgb;
+	col.rgb = col.rgb*diff.rgb;
 	
+#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/class1/deferred/attachmentShadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl
index 81961d7746053e0ebcb9570583b10b7423df5495..3f90600acefdc2d5915284c7243bee9cd8f13598 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/attachmentShadowV.glsl
@@ -39,7 +39,12 @@ void main()
 	mat = modelview_matrix * mat;
 	vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
 	
+
 	vec4 p = projection_matrix * vec4(pos, 1.0);
+#if !DEPTH_CLAMP
 	p.z = max(p.z, -p.w+0.01);
 	gl_Position = p;
+#else
+	gl_Position = p;
+#endif
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaNoColorV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaNoColorV.glsl
index 5f395801e510fa4d1a1069665518dd5beced0350..c8ddefac266f1679d90ed5c7a4c156b0cad1bc4e 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaNoColorV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarAlphaNoColorV.glsl
@@ -47,6 +47,7 @@ VARYING vec3 vary_directional;
 VARYING vec3 vary_fragcoord;
 VARYING vec3 vary_pointlight_col;
 VARYING vec2 vary_texcoord0;
+VARYING vec3 vary_norm;
 
 
 uniform float near_clip;
@@ -112,6 +113,7 @@ void main()
 	norm.y = dot(trans[1].xyz, normal);
 	norm.z = dot(trans[2].xyz, normal);
 	norm = normalize(norm);
+	vary_norm = norm;
 		
 	vec4 frag_pos = projection_matrix * pos;
 	gl_Position = frag_pos;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl
index bfd9b9b3eb4a143cfd35094d1a93f1a4a9473dca..bcccbf77d2df1e3338af941bc6e38553de6b9af1 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarF.glsl
@@ -34,6 +34,12 @@ uniform sampler2D diffuseMap;
 VARYING vec3 vary_normal;
 VARYING vec2 vary_texcoord0;
 
+vec2 encode_normal(vec3 n)
+{
+	float f = sqrt(8 * n.z + 8);
+	return n.xy / f + 0.5;
+}
+
 void main() 
 {
 	vec4 diff = texture2D(diffuseMap, vary_texcoord0.xy);
@@ -46,6 +52,6 @@ void main()
 	frag_data[0] = vec4(diff.rgb, 0.0);
 	frag_data[1] = vec4(0,0,0,0);
 	vec3 nvn = normalize(vary_normal);
-	frag_data[2] = vec4(nvn.xyz * 0.5 + 0.5, 0.0);
+	frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, 0.0);
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl
index 3686f2f647cedf8f932f2bdf4811a3fa4501423b..b809b73973bdf813d0401694bf350674e4074df2 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowF.glsl
@@ -31,12 +31,16 @@ out vec4 frag_color;
 
 uniform sampler2D diffuseMap;
 
+#if !DEPTH_CLAMP
 VARYING vec4 post_pos;
+#endif
 
 void main() 
 {
 	frag_color = vec4(1,1,1,1);
 
+#if !DEPTH_CLAMP
 	gl_FragDepth = max(post_pos.z/post_pos.w*0.5+0.5, 0.0);
+#endif
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl
index 23feb09d7233b8dea4a042712593574f06ff5b2e..bde1ad4e9f81cf70517257024554dd98fc0d33e9 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/avatarShadowV.glsl
@@ -31,7 +31,9 @@ ATTRIBUTE vec3 position;
 ATTRIBUTE vec3 normal;
 ATTRIBUTE vec2 texcoord0;
 
+#if !DEPTH_CLAMP
 VARYING vec4 post_pos;
+#endif
 
 void main()
 {
@@ -51,9 +53,13 @@ void main()
 	norm = normalize(norm);
 	
 	pos = projection_matrix * pos;
+#if !DEPTH_CLAMP
 	post_pos = pos;
 
 	gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
+#else
+	gl_Position = pos;
+#endif
 }
 
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
index f400eb7a5bc9521f9fce2c83529633cdc0b76e87..968a5f6b3df7fa57f19ca85c8f82eaed96bfb71c 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/blurLightF.glsl
@@ -46,11 +46,6 @@ VARYING vec2 vary_fragcoord;
 uniform mat4 inv_proj;
 uniform vec2 screen_res;
 
-vec3 getKern(int i)
-{
-	return kern[i];
-}
-
 vec4 getPosition(vec2 pos_screen)
 {
 	float depth = texture2DRect(depthMap, pos_screen.xy).r;
@@ -64,18 +59,53 @@ 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);
+	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;
+}
+#endif
+
 void main() 
 {
     vec2 tc = vary_fragcoord.xy;
 	vec3 norm = texture2DRect(normalMap, tc).xyz;
-	norm = vec3((norm.xy-0.5)*2.0,norm.z); // unpack norm
+	norm = decode_normal(norm.xy); // unpack norm
+
 	vec3 pos = getPosition(tc).xyz;
 	vec4 ccol = texture2DRect(lightMap, tc).rgba;
 	
 	vec2 dlt = kern_scale * delta / (1.0+norm.xy*norm.xy);
 	dlt /= max(-pos.z*dist_factor, 1.0);
 	
-	vec2 defined_weight = getKern(0).xy; // special case the first (centre) sample's weight in the blur; we have to sample it anyway so we get it for 'free'
+	vec2 defined_weight = kern[0].xy; // special case the first (centre) sample's weight in the blur; we have to sample it anyway so we get it for 'free'
 	vec4 col = defined_weight.xyxx * ccol;
 
 	// relax tolerance according to distance to avoid speckling artifacts, as angles and distances are a lot more abrupt within a small screen area at larger distances
@@ -85,28 +115,33 @@ void main()
 	float tc_mod = 0.5*(tc.x + tc.y); // mod(tc.x+tc.y,2)
 	tc_mod -= floor(tc_mod);
 	tc_mod *= 2.0;
-	tc += ( (tc_mod - 0.5) * getKern(1).z * dlt * 0.5 );
+	tc += ( (tc_mod - 0.5) * kern[1].z * dlt * 0.5 );
 
 	for (int i = 1; i < 4; i++)
 	{
-		vec2 samptc = tc + getKern(i).z*dlt;
-	        vec3 samppos = getPosition(samptc).xyz; 
+		vec2 samptc = tc + kern[i].z*dlt;
+	    vec3 samppos = getPosition(samptc).xyz; 
+
 		float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane
+		
 		if (d*d <= pointplanedist_tolerance_pow2)
 		{
-			col += texture2DRect(lightMap, samptc)*getKern(i).xyxx;
-			defined_weight += getKern(i).xy;
+			col += texture2DRect(lightMap, samptc)*kern[i].xyxx;
+			defined_weight += kern[i].xy;
 		}
 	}
+
 	for (int i = 1; i < 4; i++)
 	{
-		vec2 samptc = tc - getKern(i).z*dlt;
-	        vec3 samppos = getPosition(samptc).xyz; 
+		vec2 samptc = tc - kern[i].z*dlt;
+	    vec3 samppos = getPosition(samptc).xyz; 
+
 		float d = dot(norm.xyz, samppos.xyz-pos.xyz);// dist from plane
+		
 		if (d*d <= pointplanedist_tolerance_pow2)
 		{
-			col += texture2DRect(lightMap, samptc)*getKern(i).xyxx;
-			defined_weight += getKern(i).xy;
+			col += texture2DRect(lightMap, samptc)*kern[i].xyxx;
+			defined_weight += kern[i].xy;
 		}
 	}
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
index 23c4ea2fffd2de983595a64a35b8de10e99eee2d..595c11fae23c499cab56ae2cf4ee38a5a28c24d3 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/bumpF.glsl
@@ -39,6 +39,12 @@ VARYING vec3 vary_mat2;
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
+vec2 encode_normal(vec3 n)
+{
+	float f = sqrt(8 * n.z + 8);
+	return n.xy / f + 0.5;
+}
+
 void main() 
 {
 	vec3 col = vertex_color.rgb * texture2D(diffuseMap, vary_texcoord0.xy).rgb;
@@ -52,5 +58,5 @@ void main()
 	frag_data[1] = vertex_color.aaaa; // spec
 	//frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested
 	vec3 nvn = normalize(tnorm);
-	frag_data[2] = vec4(nvn.xyz * 0.5 + 0.5, 0.0);
+	frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, 0.0);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl
index 8ba75010a2cdf2a0c534ab94738e529e61a43e0a..10144f3e1612621f2f56f4d6fc3dab5f7853d501 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/bumpSkinnedV.glsl
@@ -30,7 +30,7 @@ ATTRIBUTE vec3 position;
 ATTRIBUTE vec4 diffuse_color;
 ATTRIBUTE vec3 normal;
 ATTRIBUTE vec2 texcoord0;
-ATTRIBUTE vec3 binormal;
+ATTRIBUTE vec4 tangent;
 
 VARYING vec3 vary_mat0;
 VARYING vec3 vary_mat1;
@@ -52,8 +52,8 @@ void main()
 	
 	
 	vec3 n = normalize((mat * vec4(normal.xyz+position.xyz, 1.0)).xyz-pos.xyz);
-	vec3 b = normalize((mat * vec4(binormal.xyz+position.xyz, 1.0)).xyz-pos.xyz);
-	vec3 t = cross(b, n);
+	vec3 t = normalize((mat * vec4(tangent.xyz+position.xyz, 1.0)).xyz-pos.xyz);
+	vec3 b = cross(n, t) * tangent.w;
 	
 	vary_mat0 = vec3(t.x, b.x, n.x);
 	vary_mat1 = vec3(t.y, b.y, n.y);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl b/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl
index c8d38bb8f74e72dd4ad681f1fb43b94cec2f6b00..9f9749394e023beaf336ff30a9bcf93b9c2203bb 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/bumpV.glsl
@@ -31,7 +31,7 @@ ATTRIBUTE vec3 position;
 ATTRIBUTE vec4 diffuse_color;
 ATTRIBUTE vec3 normal;
 ATTRIBUTE vec2 texcoord0;
-ATTRIBUTE vec3 binormal;
+ATTRIBUTE vec4 tangent;
 
 VARYING vec3 vary_mat0;
 VARYING vec3 vary_mat1;
@@ -46,8 +46,8 @@ void main()
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 	
 	vec3 n = normalize(normal_matrix * normal);
-	vec3 b = normalize(normal_matrix * binormal);
-	vec3 t = cross(b, n);
+	vec3 t = normalize(normal_matrix * tangent.xyz);
+	vec3 b = cross(n, t) * tangent.w;
 	
 	vary_mat0 = vec3(t.x, b.x, n.x);
 	vary_mat1 = vec3(t.y, b.y, n.y);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl
index c1fa9e4aac1b44b4cb9769b5b6ab57b2f679d523..7930b5d18be81a4fe3558324ff4240db66e4f2fd 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskF.glsl
@@ -37,6 +37,12 @@ VARYING vec3 vary_normal;
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
+vec2 encode_normal(vec3 n)
+{
+	float f = sqrt(8 * n.z + 8);
+	return n.xy / f + 0.5;
+}
+
 void main() 
 {
 	vec4 col = texture2D(diffuseMap, vary_texcoord0.xy) * vertex_color;
@@ -49,6 +55,6 @@ void main()
 	frag_data[0] = vec4(col.rgb, 0.0);
 	frag_data[1] = vec4(0,0,0,0); // spec
 	vec3 nvn = normalize(vary_normal);
-	frag_data[2] = vec4(nvn.xyz * 0.5 + 0.5, 0.0);
+	frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, 0.0);
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl
index 4c68123fac1680ec3d9ddfb98c64b7321c4bb7a1..59d109b886a6f8a4d9d3c7019e3f5c9353c8428d 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskIndexedF.glsl
@@ -36,6 +36,12 @@ uniform float minimum_alpha;
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
+vec2 encode_normal(vec3 n)
+{
+	float f = sqrt(8 * n.z + 8);
+	return n.xy / f + 0.5;
+}
+
 void main() 
 {
 	vec4 col = diffuseLookup(vary_texcoord0.xy) * vertex_color;
@@ -48,5 +54,5 @@ void main()
 	frag_data[0] = vec4(col.rgb, 0.0);
 	frag_data[1] = vec4(0,0,0,0);
 	vec3 nvn = normalize(vary_normal);
-	frag_data[2] = vec4(nvn.xyz * 0.5 + 0.5, 0.0);
+	frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, 0.0);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl
index ad65c7d3309c8e4f7629b26d62e383a365c43753..37d70a2412b24761fb64e8e82578452a445ba7db 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseAlphaMaskNoColorF.glsl
@@ -37,6 +37,12 @@ uniform sampler2D diffuseMap;
 VARYING vec3 vary_normal;
 VARYING vec2 vary_texcoord0;
 
+vec2 encode_normal(vec3 n)
+{
+	float f = sqrt(8 * n.z + 8);
+	return n.xy / f + 0.5;
+}
+
 void main() 
 {
 	vec4 col = texture2D(diffuseMap, vary_texcoord0.xy);
@@ -49,6 +55,6 @@ void main()
 	frag_data[0] = vec4(col.rgb, 0.0);
 	frag_data[1] = vec4(0,0,0,0); // spec
 	vec3 nvn = normalize(vary_normal);
-	frag_data[2] = vec4(nvn.xyz * 0.5 + 0.5, 0.0);
+	frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, 0.0);
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl
index 86390bdd839c108bc7b061e9f6402c28bc787212..6befb1bd8b7347e10107ae86257c1b9020ac1dc5 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseF.glsl
@@ -35,6 +35,12 @@ VARYING vec3 vary_normal;
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
+vec2 encode_normal(vec3 n)
+{
+	float f = sqrt(8 * n.z + 8);
+	return n.xy / f + 0.5;
+}
+
 void main() 
 {
 	vec3 col = vertex_color.rgb * texture2D(diffuseMap, vary_texcoord0.xy).rgb;
@@ -42,6 +48,6 @@ void main()
 	frag_data[1] = vertex_color.aaaa; // spec
 	//frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested
 	vec3 nvn = normalize(vary_normal);
-	frag_data[2] = vec4(nvn.xyz * 0.5 + 0.5, 0.0);
+	frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, 0.0);
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl
index 788b966af88bf35cb6d06fc2da80ba853a7fd334..adc361d7a2b1409863450df01437c9598ba3652e 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseIndexedF.glsl
@@ -33,13 +33,22 @@ VARYING vec3 vary_normal;
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
+vec2 encode_normal(vec3 n)
+{
+	float f = sqrt(8 * n.z + 8);
+	return n.xy / f + 0.5;
+}
+
+
 void main() 
 {
 	vec3 col = vertex_color.rgb * diffuseLookup(vary_texcoord0.xy).rgb;
+	
+	vec3 spec;
+	spec.rgb = vec3(vertex_color.a);
 
 	frag_data[0] = vec4(col, 0.0);
-	frag_data[1] = vertex_color.aaaa; // spec
-	//frag_data[1] = vec4(vec3(vertex_color.a), vertex_color.a+(1.0-vertex_color.a)*vertex_color.a); // spec - from former class3 - maybe better, but not so well tested
+	frag_data[1] = vec4(spec, vertex_color.a); // spec
 	vec3 nvn = normalize(vary_normal);
-	frag_data[2] = vec4(nvn.xyz * 0.5 + 0.5, 0.0);
+	frag_data[2] = vec4(encode_normal(nvn.xyz), vertex_color.a, 0.0);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
index 76d29b1df7dce0986ccdbe508f33cd13a42b1fdd..3c026796c8b3a7fdd9e8df4076dfbc3561c12218 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/diffuseV.glsl
@@ -47,6 +47,6 @@ void main()
 	
 	passTextureIndex();
 	vary_normal = normalize(normal_matrix * normal);
-
+	
 	vertex_color = diffuse_color;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/emissiveF.glsl b/indra/newview/app_settings/shaders/class1/deferred/emissiveF.glsl
index 6aa4d7b4ed198e29e557a6edec9b3ff5fd17a86a..ed02c4a48189f0318a100c16d13c3dd50af9f135 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/emissiveF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/emissiveF.glsl
@@ -42,7 +42,7 @@ void main()
 	float shadow = 1.0;
 
 	vec4 color = diffuseLookup(vary_texcoord0.xy)*vertex_color;
-	
+	color.rgb = pow(color.rgb, vec3(2.2));
 	color.rgb = fullbrightAtmosTransport(color.rgb);
 
 	color.rgb = fullbrightScaleSoftClip(color.rgb);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
index 36433a5827d7dde0c5ff091167ab11ecd0d8e226..dc1dead656120b9132133828001af2e5601c638e 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightF.glsl
@@ -31,6 +31,10 @@ out vec4 frag_color;
 #define frag_color gl_FragColor
 #endif
 
+#if !HAS_DIFFUSE_LOOKUP
+uniform sampler2D diffuseMap;
+#endif
+
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
@@ -40,14 +44,20 @@ vec3 fullbrightScaleSoftClip(vec3 light);
 
 void main() 
 {
-	float shadow = 1.0;
-
+#if HAS_DIFFUSE_LOOKUP
 	vec4 color = diffuseLookup(vary_texcoord0.xy)*vertex_color;
+#else
+	vec4 color = texture2D(diffuseMap, vary_texcoord0.xy)*vertex_color;
+#endif
+
+	color.rgb = pow(color.rgb,vec3(2.2f,2.2f,2.2f));
 	
 	color.rgb = fullbrightAtmosTransport(color.rgb);
 
 	color.rgb = fullbrightScaleSoftClip(color.rgb);
 
+	color.rgb = pow(color.rgb, vec3(1.0/2.2));
+
 	frag_color = color;
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..b0db9876d30a49f82f792c09ad524d5797117901
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyF.glsl
@@ -0,0 +1,72 @@
+/** 
+ * @file fullbrightShinyF.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_color;
+#else
+#define frag_color gl_FragColor
+#endif
+
+#ifndef diffuseLookup
+uniform sampler2D diffuseMap;
+#endif
+
+VARYING vec4 vertex_color;
+VARYING vec2 vary_texcoord0;
+VARYING vec3 vary_texcoord1;
+
+uniform samplerCube environmentMap;
+
+vec3 fullbrightShinyAtmosTransport(vec3 light);
+vec3 fullbrightScaleSoftClip(vec3 light);
+
+void main()
+{
+#if HAS_DIFFUSE_LOOKUP
+	vec4 color = diffuseLookup(vary_texcoord0.xy);
+#else
+	vec4 color = texture2D(diffuseMap, vary_texcoord0.xy);
+#endif
+
+	
+	color.rgb *= vertex_color.rgb;
+	
+	vec3 envColor = textureCube(environmentMap, vary_texcoord1.xyz).rgb;	
+	color.rgb = mix(color.rgb, envColor.rgb, vertex_color.a);
+
+	color.rgb = pow(color.rgb,vec3(2.2f,2.2f,2.2f));
+	
+	color.rgb = fullbrightShinyAtmosTransport(color.rgb);
+	color.rgb = fullbrightScaleSoftClip(color.rgb);
+
+	color.a = 1.0;
+
+	color.rgb = pow(color.rgb, vec3(1.0/2.2));
+
+	frag_color = color;
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..34bd8d445a0eb532d77e10ea45897715bc369c65
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightShinyV.glsl
@@ -0,0 +1,67 @@
+/**
+ * @file fullbrightShinyV.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 texture_matrix1;
+uniform mat4 modelview_matrix;
+uniform mat4 modelview_projection_matrix;
+
+
+void calcAtmospherics(vec3 inPositionEye);
+
+uniform vec4 origin;
+
+
+
+ATTRIBUTE vec3 position;
+void passTextureIndex();
+ATTRIBUTE vec3 normal;
+ATTRIBUTE vec4 diffuse_color;
+ATTRIBUTE vec2 texcoord0;
+
+VARYING vec4 vertex_color;
+VARYING vec2 vary_texcoord0;
+VARYING vec3 vary_texcoord1;
+
+
+void main()
+{
+	//transform vertex
+	vec4 vert = vec4(position.xyz,1.0);
+	passTextureIndex();
+	vec4 pos = (modelview_matrix * vert);
+	gl_Position = modelview_projection_matrix*vec4(position.xyz, 1.0);
+	
+	vec3 norm = normalize(normal_matrix * normal);
+	vec3 ref = reflect(pos.xyz, -norm);
+
+	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
+	vary_texcoord1 = (texture_matrix1*vec4(ref,1.0)).xyz;
+
+	calcAtmospherics(pos.xyz);
+
+	vertex_color = diffuse_color;
+}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
index 2e6982d101791c337bb96c3775a40cdd0912a821..3f09a153754d8c24333fed5465fb7ca6f17a880d 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/fullbrightV.glsl
@@ -57,8 +57,6 @@ void main()
 	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
 	
 	calcAtmospherics(pos.xyz);
-	
-	vertex_color = diffuse_color;
 
-	
+	vertex_color = diffuse_color;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..618ea747f58c87d8b724b3da3593decb7222dd96
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/materialF.glsl
@@ -0,0 +1,696 @@
+/** 
+ * @file materialF.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$
+ */
+ 
+#define DIFFUSE_ALPHA_MODE_IGNORE	0
+#define DIFFUSE_ALPHA_MODE_BLEND	1
+#define DIFFUSE_ALPHA_MODE_MASK		2
+#define DIFFUSE_ALPHA_MODE_EMISSIVE 3
+
+uniform float emissive_brightness;
+
+#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
+
+#ifdef DEFINE_GL_FRAGCOLOR
+out vec4 frag_color;
+#else
+#define frag_color gl_FragColor
+#endif
+
+#if HAS_SUN_SHADOW
+
+uniform sampler2DShadow shadowMap0;
+uniform sampler2DShadow shadowMap1;
+uniform sampler2DShadow shadowMap2;
+uniform sampler2DShadow shadowMap3;
+
+uniform mat4 shadow_matrix[6];
+uniform vec4 shadow_clip;
+uniform vec2 shadow_res;
+uniform float shadow_bias;
+
+float pcfShadow(sampler2DShadow shadowMap, vec4 stc)
+{
+	stc.xyz /= stc.w;
+	stc.z += shadow_bias;
+		
+	stc.x = floor(stc.x*shadow_res.x + fract(stc.y*shadow_res.y*12345))/shadow_res.x; // add some chaotic jitter to X sample pos according to Y to disguise the snapping going on here
+	
+	float cs = shadow2D(shadowMap, stc.xyz).x;
+	float shadow = cs;
+	
+    shadow += shadow2D(shadowMap, stc.xyz+vec3(2.0/shadow_res.x, 1.5/shadow_res.y, 0.0)).x;
+    shadow += shadow2D(shadowMap, stc.xyz+vec3(1.0/shadow_res.x, -1.5/shadow_res.y, 0.0)).x;
+    shadow += shadow2D(shadowMap, stc.xyz+vec3(-1.0/shadow_res.x, 1.5/shadow_res.y, 0.0)).x;
+    shadow += shadow2D(shadowMap, stc.xyz+vec3(-2.0/shadow_res.x, -1.5/shadow_res.y, 0.0)).x;
+                       
+    return shadow*0.2;
+}
+
+#endif
+
+uniform samplerCube environmentMap;
+uniform sampler2D	  lightFunc;
+
+// Inputs
+uniform vec4 morphFactor;
+uniform vec3 camPosLocal;
+//uniform vec4 camPosWorld;
+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;
+VARYING vec2 vary_fragcoord;
+
+VARYING vec3 vary_position;
+
+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];
+
+vec3 calcDirectionalLight(vec3 n, vec3 l)
+{
+	float a = max(dot(n,l),0.0);
+	return vec3(a,a,a);
+}
+
+
+vec3 calcPointLightOrSpotLight(vec3 light_col, vec3 npos, vec3 diffuse, vec4 spec, vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight, inout float glare)
+{
+	//get light vector
+	vec3 lv = lp.xyz-v;
+	
+	//get distance
+	float d = length(lv);
+	
+	float da = 1.0;
+
+	vec3 col = vec3(0,0,0);
+
+	if (d > 0.0 && la > 0.0 && fa > 0.0)
+	{
+		//normalize light vector
+		lv = normalize(lv);
+	
+		//distance attenuation
+		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;
+
+		// 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);		
+		
+		float lit = max(da * dist_atten, 0.0);
+
+		col = light_col*lit*diffuse;
+
+		if (spec.a > 0.0)
+		{
+			//vec3 ref = dot(pos+lv, norm);
+			vec3 h = normalize(lv+npos);
+			float nh = dot(n, h);
+			float nv = dot(n, 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);
+				vec3 speccol = lit*scol*light_col.rgb*spec.rgb;
+				col += speccol;
+
+				float cur_glare = max(speccol.r, speccol.g);
+				cur_glare = max(cur_glare, speccol.b);
+				glare = max(glare, speccol.r);
+				glare += max(cur_glare, 0.0);
+				//col += spec.rgb;
+			}
+		}
+	}
+
+	return max(col, vec3(0.0,0.0,0.0));	
+
+}
+
+vec4 getPosition_d(vec2 pos_screen, float depth)
+{
+	vec2 sc = pos_screen.xy*2.0;
+	sc /= screen_res;
+	sc -= vec2(1.0,1.0);
+	vec4 ndc = vec4(sc.x, sc.y, 2.0*depth-1.0, 1.0);
+	vec4 pos = inv_proj * ndc;
+	pos /= pos.w;
+	pos.w = 1.0;
+	return pos;
+}
+
+vec3 getPositionEye()
+{
+	return vary_PositionEye;
+}
+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;
+}
+
+#else
+#ifdef DEFINE_GL_FRAGCOLOR
+out vec4 frag_data[3];
+#else
+#define frag_data gl_FragData
+#endif
+#endif
+
+uniform sampler2D diffuseMap;
+
+#if HAS_NORMAL_MAP
+uniform sampler2D bumpMap;
+#endif
+
+#if HAS_SPECULAR_MAP
+uniform sampler2D specularMap;
+
+VARYING vec2 vary_texcoord2;
+#endif
+
+uniform float env_intensity;
+uniform vec4 specular_color;  // specular color RGB and specular exponent (glossiness) in alpha
+
+#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_MASK)
+uniform float minimum_alpha;
+#endif
+
+#if HAS_NORMAL_MAP
+VARYING vec3 vary_mat0;
+VARYING vec3 vary_mat1;
+VARYING vec3 vary_mat2;
+VARYING vec2 vary_texcoord1;
+#else
+VARYING vec3 vary_normal;
+#endif
+
+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);
+	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;
+}
+#endif
+
+void main() 
+{
+	vec4 diffcol = texture2D(diffuseMap, vary_texcoord0.xy);
+	diffcol.rgb *= vertex_color.rgb;
+
+#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_MASK)
+	if (diffcol.a < minimum_alpha)
+	{
+		discard;
+	}
+#endif
+
+#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
+	vec3 old_diffcol = diffcol.rgb;
+	diffcol.rgb = pow(diffcol.rgb, vec3(2.2));
+#endif
+
+#if HAS_SPECULAR_MAP
+	vec4 spec = texture2D(specularMap, vary_texcoord2.xy);
+	spec.rgb *= specular_color.rgb;
+#else
+	vec4 spec = vec4(specular_color.rgb, 1.0);
+#endif
+
+#if HAS_NORMAL_MAP
+	vec4 norm = texture2D(bumpMap, vary_texcoord1.xy);
+
+	norm.xyz = norm.xyz * 2 - 1;
+
+	vec3 tnorm = vec3(dot(norm.xyz,vary_mat0),
+			  dot(norm.xyz,vary_mat1),
+			  dot(norm.xyz,vary_mat2));
+#else
+	vec4 norm = vec4(0,0,0,1.0);
+	vec3 tnorm = vary_normal;
+#endif
+
+    norm.xyz = tnorm;
+    norm.xyz = normalize(norm.xyz);
+
+	vec4 final_color = diffcol;
+	
+#if (DIFFUSE_ALPHA_MODE != DIFFUSE_ALPHA_MODE_EMISSIVE)
+	final_color.a = emissive_brightness;
+#else
+	final_color.a = max(final_color.a, emissive_brightness);
+#endif
+
+	vec4 final_specular = spec;
+#if HAS_SPECULAR_MAP
+	vec4 final_normal = vec4(encode_normal(normalize(tnorm)), env_intensity * spec.a, 0.0);
+	final_specular.a = specular_color.a * norm.a;
+#else
+	vec4 final_normal = vec4(encode_normal(normalize(tnorm)), env_intensity, 0.0);
+	final_specular.a = specular_color.a;
+#endif
+	
+
+#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
+		//forward rendering, output just lit RGBA
+	vec3 pos = vary_position;
+
+#if HAS_SUN_SHADOW
+	float shadow = 0.0;
+	
+	vec4 spos = vec4(pos,1.0);
+		
+	if (spos.z > -shadow_clip.w)
+	{	
+		vec4 lpos;
+		
+		vec4 near_split = shadow_clip*-0.75;
+		vec4 far_split = shadow_clip*-1.25;
+		vec4 transition_domain = near_split-far_split;
+		float weight = 0.0;
+
+		if (spos.z < near_split.z)
+		{
+			lpos = shadow_matrix[3]*spos;
+			
+			float w = 1.0;
+			w -= max(spos.z-far_split.z, 0.0)/transition_domain.z;
+			shadow += pcfShadow(shadowMap3, lpos)*w;
+			weight += w;
+			shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0);
+		}
+
+		if (spos.z < near_split.y && spos.z > far_split.z)
+		{
+			lpos = shadow_matrix[2]*spos;
+			
+			float w = 1.0;
+			w -= max(spos.z-far_split.y, 0.0)/transition_domain.y;
+			w -= max(near_split.z-spos.z, 0.0)/transition_domain.z;
+			shadow += pcfShadow(shadowMap2, lpos)*w;
+			weight += w;
+		}
+
+		if (spos.z < near_split.x && spos.z > far_split.y)
+		{
+			lpos = shadow_matrix[1]*spos;
+			
+			float w = 1.0;
+			w -= max(spos.z-far_split.x, 0.0)/transition_domain.x;
+			w -= max(near_split.y-spos.z, 0.0)/transition_domain.y;
+			shadow += pcfShadow(shadowMap1, lpos)*w;
+			weight += w;
+		}
+
+		if (spos.z > far_split.x)
+		{
+			lpos = shadow_matrix[0]*spos;
+							
+			float w = 1.0;
+			w -= max(near_split.x-spos.z, 0.0)/transition_domain.x;
+				
+			shadow += pcfShadow(shadowMap0, lpos)*w;
+			weight += w;
+		}
+		
+
+		shadow /= weight;
+	}
+	else
+	{
+		shadow = 1.0;
+	}
+#else
+	float shadow = 1.0;
+#endif
+
+	spec = final_specular;
+	vec4 diffuse = final_color;
+	float envIntensity = final_normal.z;
+
+    vec3 col = vec3(0.0f,0.0f,0.0f);
+
+	float bloom = 0.0;
+	calcAtmospherics(pos.xyz, 1.0);
+	
+	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, 0.0f);
+
+	col.rgb = atmosAmbient(col);
+	
+	float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 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;
+	
+
+	float glare = 0.0;
+
+	if (spec.a > 0.0) // specular reflection
+	{
+		// the old infinite-sky shiny reflection
+		//
+				
+		float sa = dot(refnormpersp, sun_dir.xyz);
+		vec3 dumbshiny = vary_SunlitColor*shadow*(texture2D(lightFunc, vec2(sa, spec.a)).r);
+							
+		// add the two types of shiny together
+		vec3 spec_contrib = dumbshiny * spec.rgb;
+		bloom = dot(spec_contrib, spec_contrib) / 6;
+
+		glare = max(spec_contrib.r, spec_contrib.g);
+		glare = max(glare, spec_contrib.b);
+
+		col += spec_contrib;
+	}
+
+	col = mix(col.rgb, old_diffcol.rgb, diffuse.a);
+
+	if (envIntensity > 0.0)
+	{
+		//add environmentmap
+		vec3 env_vec = env_mat * refnormpersp;
+		
+		vec3 refcol = textureCube(environmentMap, env_vec).rgb;
+
+		col = mix(col.rgb, refcol, 
+			envIntensity);  
+
+		float cur_glare = max(refcol.r, refcol.g);
+		cur_glare = max(cur_glare, refcol.b);
+		cur_glare *= envIntensity*4.0;
+		glare += cur_glare;
+	}
+
+	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));
+
+			
+	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);
+
+		LIGHT_LOOP(1)
+		LIGHT_LOOP(2)
+		LIGHT_LOOP(3)
+		LIGHT_LOOP(4)
+		LIGHT_LOOP(5)
+		LIGHT_LOOP(6)
+		LIGHT_LOOP(7)
+
+
+	//convert to gamma space for display on screen
+	col.rgb = pow(col.rgb, vec3(1.0/2.2));
+
+	frag_color.rgb = col.rgb;
+	glare = min(glare, 1.0);
+	frag_color.a = max(diffcol.a,glare)*vertex_color.a;
+
+#else
+	frag_data[0] = final_color;
+	frag_data[1] = final_specular; // XYZ = Specular color. W = Specular exponent.
+	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
new file mode 100644
index 0000000000000000000000000000000000000000..b25032866ba5b7d8a63832a18647f1a9502e36cb
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/materialV.glsl
@@ -0,0 +1,144 @@
+/** 
+ * @file bumpV.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$
+ */
+
+#define DIFFUSE_ALPHA_MODE_IGNORE 0
+#define DIFFUSE_ALPHA_MODE_BLEND 1
+#define DIFFUSE_ALPHA_MODE_MASK 2
+#define DIFFUSE_ALPHA_MODE_EMISSIVE 3
+
+#if HAS_SKIN
+uniform mat4 modelview_matrix;
+uniform mat4 projection_matrix;
+mat4 getObjectSkinnedTransform();
+#else
+uniform mat3 normal_matrix;
+uniform mat4 modelview_projection_matrix;
+#endif
+
+#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
+
+#if !HAS_SKIN
+uniform mat4 modelview_matrix;
+#endif
+
+VARYING vec3 vary_position;
+
+#endif
+
+uniform mat4 texture_matrix0;
+
+ATTRIBUTE vec3 position;
+ATTRIBUTE vec4 diffuse_color;
+ATTRIBUTE vec3 normal;
+ATTRIBUTE vec2 texcoord0;
+
+
+#if HAS_NORMAL_MAP
+ATTRIBUTE vec4 tangent;
+ATTRIBUTE vec2 texcoord1;
+
+VARYING vec3 vary_mat0;
+VARYING vec3 vary_mat1;
+VARYING vec3 vary_mat2;
+
+VARYING vec2 vary_texcoord1;
+#else
+VARYING vec3 vary_normal;
+#endif
+
+#if HAS_SPECULAR_MAP
+ATTRIBUTE vec2 texcoord2;
+VARYING vec2 vary_texcoord2;
+#endif
+ 
+VARYING vec4 vertex_color;
+VARYING vec2 vary_texcoord0;
+
+void main()
+{
+#if HAS_SKIN
+	mat4 mat = getObjectSkinnedTransform();
+
+	mat = modelview_matrix * mat;
+
+	vec3 pos = (mat*vec4(position.xyz,1.0)).xyz;
+
+#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
+	vary_position = pos;
+#endif
+
+	gl_Position = projection_matrix*vec4(pos,1.0);
+
+#else
+	//transform vertex
+	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0); 
+
+#endif
+	
+	vary_texcoord0 = (texture_matrix0 * vec4(texcoord0,0,1)).xy;
+	
+#if HAS_NORMAL_MAP
+	vary_texcoord1 = (texture_matrix0 * vec4(texcoord1,0,1)).xy;
+#endif
+
+#if HAS_SPECULAR_MAP
+	vary_texcoord2 = (texture_matrix0 * vec4(texcoord2,0,1)).xy;
+#endif
+
+#if HAS_SKIN
+	vec3 n = normalize((mat*vec4(normal.xyz+position.xyz,1.0)).xyz-pos.xyz);
+#if HAS_NORMAL_MAP
+	vec3 t = normalize((mat*vec4(tangent.xyz+position.xyz,1.0)).xyz-pos.xyz);
+	vec3 b = cross(n, t)*tangent.w;
+	
+	vary_mat0 = vec3(t.x, b.x, n.x);
+	vary_mat1 = vec3(t.y, b.y, n.y);
+	vary_mat2 = vec3(t.z, b.z, n.z);
+#else //HAS_NORMAL_MAP
+vary_normal  = n;
+#endif //HAS_NORMAL_MAP
+#else //HAS_SKIN
+	vec3 n = normalize(normal_matrix * normal);
+#if HAS_NORMAL_MAP
+	vec3 t = normalize(normal_matrix * tangent.xyz);
+	vec3 b = cross(n,t)*tangent.w;
+	//vec3 t = cross(b,n) * binormal.w;
+	
+	vary_mat0 = vec3(t.x, b.x, n.x);
+	vary_mat1 = vec3(t.y, b.y, n.y);
+	vary_mat2 = vec3(t.z, b.z, n.z);
+#else //HAS_NORMAL_MAP
+	vary_normal = n;
+#endif //HAS_NORMAL_MAP
+#endif //HAS_SKIN
+	
+	vertex_color = diffuse_color;
+
+#if (DIFFUSE_ALPHA_MODE == DIFFUSE_ALPHA_MODE_BLEND)
+#if !HAS_SKIN
+	vary_position = (modelview_matrix*vec4(position.xyz, 1.0)).xyz;
+#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 7e79317543f4f7441049e57037bfbbb126306640..868526d457eb61e9b22106aec75525ed58b115d5 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/multiPointLightF.glsl
@@ -56,6 +56,40 @@ 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);
+	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;
+}
+#endif
+
 vec4 getPosition(vec2 pos_screen)
 {
 	float depth = texture2DRect(depthMap, pos_screen.xy).r;
@@ -79,7 +113,7 @@ void main()
 	}
 	
 	vec3 norm = texture2DRect(normalMap, frag.xy).xyz;
-	norm = (norm.xyz-0.5)*2.0; // unpack norm
+	norm = decode_normal(norm.xy); // unpack norm
 	norm = normalize(norm);
 	vec4 spec = texture2DRect(specularRect, frag.xy);
 	vec3 diff = texture2DRect(diffuseRect, frag.xy).rgb;
@@ -93,9 +127,9 @@ void main()
 		bool light_contrib = (i < light_count);
 		
 		vec3 lv = light[i].xyz-pos;
-		float dist2 = dot(lv,lv);
-		dist2 /= light[i].w;
-		if (dist2 > 1.0)
+		float dist = length(lv);
+		dist /= light[i].w;
+		if (dist > 1.0)
 		{
 			light_contrib = false;
 		}
@@ -110,27 +144,39 @@ void main()
 		{
 			lv = normalize(lv);
 			da = dot(norm, lv);
-					
+			
 			float fa = light_col[i].a+1.0;
-			float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 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;
 
 			float lit = da * dist_atten;
-			
+						
 			vec3 col = light_col[i].rgb*lit*diff;
+			
 			//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);
-				
-				float sa = dot(normalize(lv+npos),norm);
-				
-				if (sa > 0.0)
+				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)
 				{
-					sa = 6 * texture2D(lightFunc, vec2(sa, spec.a)).r * min(dist_atten*4.0, 1.0);
-					sa *= noise;
-					col += da*sa*light_col[i].rgb*spec.rgb;
+					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;
 				}
 			}
 			
diff --git a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
index bff87cb6aac7499a1ae030a8b6fac365c9ee19e2..97bf49a605b0e5346cdca1736a275d0d4a3113ec 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/multiSpotLightF.glsl
@@ -40,6 +40,7 @@ uniform sampler2DRect normalMap;
 uniform samplerCube environmentMap;
 uniform sampler2D noiseMap;
 uniform sampler2D projectionMap;
+uniform sampler2D lightFunc;
 
 uniform mat4 proj_mat; //screen space to light space
 uniform float proj_near; //near clip for projection
@@ -66,9 +67,49 @@ 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);
+	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;
+}
+#endif
+
+vec4 correctWithGamma(vec4 col)
+{
+	return vec4(pow(col.rgb, vec3(2.2)), col.a);
+}
+
 vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
 {
 	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	ret = correctWithGamma(ret);
 	
 	vec2 dist = tc-vec2(0.5);
 	
@@ -84,6 +125,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);
 	
 	vec2 dist = vec2(0.5) - abs(tc-vec2(0.5));
 	
@@ -101,6 +143,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);
 	
 	vec2 dist = tc-vec2(0.5);
 	
@@ -134,15 +177,17 @@ void main()
 	
 	vec3 pos = getPosition(frag.xy).xyz;
 	vec3 lv = center.xyz-pos.xyz;
-	float dist2 = dot(lv,lv);
-	dist2 /= size;
-	if (dist2 > 1.0)
+	float dist = length(lv);
+	dist /= size;
+	if (dist > 1.0)
 	{
 		discard;
 	}
 		
 	vec3 norm = texture2DRect(normalMap, frag.xy).xyz;
-	norm = vec3((norm.xy-0.5)*2.0, norm.z);
+	float envIntensity = norm.z;
+
+	norm = decode_normal(norm.xy);
 	
 	norm = normalize(norm);
 	float l_dist = -dot(lv, proj_n);
@@ -156,7 +201,10 @@ void main()
 	proj_tc.xyz /= proj_tc.w;
 	
 	float fa = falloff+1.0;
-	float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0);
+	float dist_atten = min(1.0-(dist-1.0*(1.0-fa))/fa, 1.0);
+	dist_atten *= dist_atten;
+	dist_atten *= 2.0;
+
 	if (dist_atten <= 0.0)
 	{
 		discard;
@@ -169,7 +217,8 @@ void main()
 	vec3 col = vec3(0,0,0);
 		
 	vec3 diff_tex = texture2DRect(diffuseRect, frag.xy).rgb;
-		
+	vec3 dlit = vec3(0, 0, 0);
+	
 	float noise = texture2D(noiseMap, frag.xy/128.0).b;
 	if (proj_tc.z > 0.0 &&
 		proj_tc.x < 1.0 &&
@@ -187,14 +236,13 @@ void main()
 			
 			vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod);
 		
-			vec3 lcol = color.rgb * plcol.rgb * plcol.a;
+			dlit = color.rgb * plcol.rgb * plcol.a;
 			
 			lit = da * dist_atten * noise;
 			
-			col = lcol*lit*diff_tex;
+			col = dlit*lit*diff_tex;
 			amb_da += (da*0.5)*proj_ambiance;
 		}
-		
 		//float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0);
 		vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod);
 							
@@ -203,13 +251,38 @@ void main()
 		amb_da *= dist_atten * noise;
 			
 		amb_da = min(amb_da, 1.0-lit);
-			
-		col += amb_da*color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a;
+		col += amb_da*color.rgb*diff_tex*amb_plcol.rgb*amb_plcol.a;
 	}
 	
 	
 	vec4 spec = texture2DRect(specularRect, frag.xy);
+	
 	if (spec.a > 0.0)
+	{
+		dlit *= min(da*6.0, 1.0) * dist_atten;
+
+		vec3 npos = -normalize(pos);
+
+		//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 += dlit*scol*spec.rgb;
+			//col += spec.rgb;
+		}
+	}	
+
+	if (envIntensity > 0.0)
 	{
 		vec3 ref = reflect(normalize(pos), norm);
 		
@@ -227,8 +300,9 @@ void main()
 			{
 				stc.xy /= stc.w;
 
-				float fatten = clamp(spec.a*spec.a+spec.a*0.5, 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 &&
@@ -236,8 +310,7 @@ void main()
 					stc.x > 0.0 &&
 					stc.y > 0.0)
 				{
-					vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
-					col += dist_atten*scol.rgb*color.rgb*scol.a*spec.rgb;
+					col += color.rgb*texture2DLodSpecular(projectionMap, stc.xy, proj_lod-envIntensity*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 75757b26c83f36af3f135b22962948974fde3095..caf20ce707e6b45f5d01f1a1c034e6d3308be014 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightF.glsl
@@ -54,6 +54,40 @@ 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);
+	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;
+}
+#endif
+
 vec4 getPosition(vec2 pos_screen)
 {
 	float depth = texture2DRect(depthMap, pos_screen.xy).r;
@@ -76,15 +110,15 @@ void main()
 	
 	vec3 pos = getPosition(frag.xy).xyz;
 	vec3 lv = trans_center.xyz-pos;
-	float dist2 = dot(lv,lv);
-	dist2 /= size;
-	if (dist2 > 1.0)
+	float dist = length(lv);
+	dist /= size;
+	if (dist > 1.0)
 	{
 		discard;
 	}
 	
 	vec3 norm = texture2DRect(normalMap, frag.xy).xyz;
-	norm = (norm.xyz-0.5)*2.0; // unpack norm
+	norm = decode_normal(norm.xy); // unpack norm
 	float da = dot(norm, lv);
 	if (da < 0.0)
 	{
@@ -99,20 +133,33 @@ void main()
 	
 	vec3 col = texture2DRect(diffuseRect, frag.xy).rgb;
 	float fa = falloff+1.0;
-	float dist_atten = clamp(1.0-(dist2-1.0*(1.0-fa))/fa, 0.0, 1.0);
-	float lit = da * dist_atten * noise;
+	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 lit = da * dist_atten * noise;
+
 	col = color.rgb*lit*col;
 
 	vec4 spec = texture2DRect(specularRect, frag.xy);
 	if (spec.a > 0.0)
 	{
-		float sa = dot(normalize(lv-normalize(pos)),norm);
-		if (sa > 0.0)
+		lit = min(da*6.0, 1.0) * dist_atten;
+
+		vec3 npos = -normalize(pos);
+		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)
 		{
-			sa = 6 * texture2D(lightFunc, vec2(sa, spec.a)).r * min(dist_atten*4.0, 1.0);
-			sa *= noise;
-			col += da*sa*color.rgb*spec.rgb;
+			float scol = fres*texture2D(lightFunc, vec2(nh, spec.a)).r*gt/(nh*da);
+			col += lit*scol*color.rgb*spec.rgb;
 		}
 	}
 	
diff --git a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl
index 9491421236d49d0ad05f8220274498c75809a54e..a5625fbc16e1f567a41ff5f806ab187481a039ee 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/pointLightV.glsl
@@ -37,7 +37,7 @@ VARYING vec3 trans_center;
 void main()
 {
 	//transform vertex
-	vec3 p = position*sqrt(size)+center;
+	vec3 p = position*size+center;
 	vec4 pos = modelview_projection_matrix * vec4(p.xyz, 1.0);
 	vary_fragcoord = pos;
 	trans_center = (modelview_matrix*vec4(center.xyz, 1.0)).xyz;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..6f2cfae6d2381e416712c2564ab96125dbf0edc8
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/deferred/postDeferredGammaCorrect.glsl
@@ -0,0 +1,46 @@
+/** 
+ * @file postDeferredGammaCorrect.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$
+ */
+ 
+#extension GL_ARB_texture_rectangle : enable
+
+#ifdef DEFINE_GL_FRAGCOLOR
+out vec4 frag_color;
+#else
+#define frag_color gl_FragColor
+#endif
+
+uniform sampler2DRect diffuseRect;
+
+uniform vec2 screen_res;
+VARYING vec2 vary_fragcoord;
+
+uniform float texture_gamma;
+
+void main() 
+{
+	vec4 diff = texture2DRect(diffuseRect, vary_fragcoord);
+	frag_color = pow(diff, vec4(texture_gamma, texture_gamma, texture_gamma, 1.0f));
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskF.glsl
index bced4a557774cc6cc9037e43ea7097f0cba3a7a1..91a96977f06c15dd306fdf64d8360b7bae9c4e70 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskF.glsl
@@ -31,8 +31,12 @@ out vec4 frag_color;
 
 uniform sampler2D diffuseMap;
 
+#if !DEPTH_CLAMP
 VARYING float pos_zd2;
+#endif
+
 VARYING float pos_w;
+
 VARYING float target_pos_x;
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
@@ -56,5 +60,7 @@ void main()
 
 	frag_color = vec4(1,1,1,1);
 	
+#if !DEPTH_CLAMP
 	gl_FragDepth = max(pos_zd2/pos_w+0.5, 0.0);
+#endif
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskV.glsl
index c1f2d90712c42b0ba81a40b23a759b0122672ccb..11411a605c69d04774360a525579aae4d5e449a6 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowAlphaMaskV.glsl
@@ -31,8 +31,12 @@ ATTRIBUTE vec3 position;
 ATTRIBUTE vec4 diffuse_color;
 ATTRIBUTE vec2 texcoord0;
 
+#if !DEPTH_CLAMP
 VARYING float pos_zd2;
+#endif
+
 VARYING float pos_w;
+
 VARYING float target_pos_x;
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
@@ -45,10 +49,16 @@ void main()
 	vec4 pre_pos = vec4(position.xyz, 1.0);
 	vec4 pos = modelview_projection_matrix * pre_pos;
 	target_pos_x = 0.5 * (shadow_target_width - 1.0) * pos.x;
+
 	pos_w = pos.w;
+
+#if !DEPTH_CLAMP
 	pos_zd2 = pos.z * 0.5;
 	
 	gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
+#else
+	gl_Position = pos;
+#endif
 	
 	passTextureIndex();
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl
index 6195e2f1ecb30ff4d115595edae972e96f673184..ef153dfc5be3d3cb92838d8efdd1c72ea1d9ba47 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowCubeV.glsl
@@ -27,7 +27,9 @@ uniform mat4 modelview_projection_matrix;
 
 ATTRIBUTE vec3 position;
 
+#if !DEPTH_CLAMP
 VARYING vec4 post_pos;
+#endif
 
 uniform vec3 box_center;
 uniform vec3 box_size;
@@ -37,8 +39,12 @@ void main()
 	//transform vertex
 	vec3 p = position*box_size+box_center;
 	vec4 pos = modelview_projection_matrix*vec4(p.xyz, 1.0);
-	
+
+#if !DEPTH_CLAMP
 	post_pos = pos;
-	
+
 	gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
+#else
+	gl_Position = pos;
+#endif
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl
index 7e55fdc12a4bf5f943c3b6c930298e3647a4ed17..3d1b1828755a2a5e54723efa9c6f32f078e415d1 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowF.glsl
@@ -29,11 +29,16 @@ out vec4 frag_color;
 #define frag_color gl_FragColor
 #endif
 
+#if !DEPTH_CLAMP
 VARYING vec4 post_pos;
+#endif
 
 void main() 
 {
 	frag_color = vec4(1,1,1,1);
 	
+#if !DEPTH_CLAMP
 	gl_FragDepth = max(post_pos.z/post_pos.w*0.5+0.5, 0.0);
+#endif
+
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl b/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl
index 8b46e81f90c03a12ed5d3b4ade3cf217c920d5db..cc77a4cea059729e64d2c67cefc9cb5032c8cb48 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/shadowV.glsl
@@ -27,14 +27,20 @@ uniform mat4 modelview_projection_matrix;
 
 ATTRIBUTE vec3 position;
 
+#if !DEPTH_CLAMP
 VARYING vec4 post_pos;
+#endif
 
 void main()
 {
 	//transform vertex
 	vec4 pos = modelview_projection_matrix*vec4(position.xyz, 1.0);
 	
+#if !DEPTH_CLAMP
 	post_pos = pos;
-	
+
 	gl_Position = vec4(pos.x, pos.y, pos.w*0.5, pos.w);
+#else
+	gl_Position = pos;
+#endif
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl b/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl
index faa54a316e8663b2baa59d5ad8185e5a948fa800..22f4729e2e3f8a8e7f9af025e5ce65f72a20d4f9 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/skyF.glsl
@@ -61,6 +61,6 @@ void main()
 	/// Gamma correct for WL (soft clip effect).
 	frag_data[0] = vec4(scaleSoftClip(color.rgb), 1.0);
 	frag_data[1] = vec4(0.0,0.0,0.0,0.0);
-	frag_data[2] = vec4(0,0,1,0);
+	frag_data[2] = vec4(0.5,0.5,0.0,1.0); //1.0 in norm.w masks off fog
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
index 89448e2167a2dddf414aa7f6baff508775f5dc80..08583ad0f2f7804c7fbf943288381fb7f925efdb 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightF.glsl
@@ -60,6 +60,7 @@ uniform float density_multiplier;
 uniform float distance_multiplier;
 uniform float max_y;
 uniform vec4 glow;
+uniform float global_gamma;
 uniform float scene_light_strength;
 uniform mat3 env_mat;
 uniform mat3 ssao_effect_mat;
@@ -77,6 +78,34 @@ vec3 vary_AtmosAttenuation;
 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
+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;
+}
+#endif
+
 vec4 getPosition_d(vec2 pos_screen, float depth)
 {
 	vec2 sc = pos_screen.xy*2.0;
@@ -116,7 +145,6 @@ vec3 getAtmosAttenuation()
 	return vary_AtmosAttenuation;
 }
 
-
 void setPositionEye(vec3 v)
 {
 	vary_PositionEye = v;
@@ -237,6 +265,15 @@ vec3 atmosTransport(vec3 light) {
 	light += getAdditiveColor() * 2.0;
 	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 atmosGetDiffuseSunlightColor()
 {
 	return getSunlitColor();
@@ -271,57 +308,88 @@ vec3 scaleSoftClip(vec3 light)
 	return light;
 }
 
+
+vec3 fullbrightScaleSoftClip(vec3 light)
+{
+	//soft clip effect:
+	return light;
+}
+
 void main() 
 {
 	vec2 tc = vary_fragcoord.xy;
 	float depth = texture2DRect(depthMap, tc.xy).r;
 	vec3 pos = getPosition_d(tc, depth).xyz;
-	vec3 norm = texture2DRect(normalMap, tc).xyz;
-	norm = (norm.xyz-0.5)*2.0; // unpack norm
+	vec4 norm = texture2DRect(normalMap, tc);
+	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);
+
 	vec4 diffuse = texture2DRect(diffuseRect, tc);
+
+	//convert to gamma space
+	diffuse.rgb = pow(diffuse.rgb, vec3(1.0/2.2));
+
 	vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy);
-	
 	vec3 col;
 	float bloom = 0.0;
-	if (diffuse.a < 0.9)
 	{
 		calcAtmospherics(pos.xyz, 1.0);
 	
 		col = atmosAmbient(vec3(0));
-		col += atmosAffectDirectionalLight(max(min(da, 1.0), diffuse.a));
+		float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 1.0);
+		ambient *= 0.5;
+		ambient *= ambient;
+		ambient = (1.0-ambient);
+
+		col.rgb *= ambient;
+
+		col += atmosAffectDirectionalLight(max(min(da, 1.0), 0.0));
 	
 		col *= diffuse.rgb;
 	
+		vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
+
 		if (spec.a > 0.0) // specular reflection
 		{
 			// the old infinite-sky shiny reflection
 			//
-			vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
+			
 			float sa = dot(refnormpersp, sun_dir.xyz);
-			vec3 dumbshiny = vary_SunlitColor*(6 * texture2D(lightFunc, vec2(sa, spec.a)).r);
+			vec3 dumbshiny = vary_SunlitColor*(texture2D(lightFunc, vec2(sa, spec.a)).r);
 			
 			// add the two types of shiny together
 			vec3 spec_contrib = dumbshiny * spec.rgb;
-			bloom = dot(spec_contrib, spec_contrib) / 4;
+			bloom = dot(spec_contrib, spec_contrib) / 6;
 			col += spec_contrib;
-
-			//add environmentmap
+		}
+		
+		
+		col = mix(col.rgb, diffuse.rgb, diffuse.a);
+				
+		if (envIntensity > 0.0)
+		{ //add environmentmap
 			vec3 env_vec = env_mat * refnormpersp;
-			col = mix(col.rgb, textureCube(environmentMap, env_vec).rgb, 
-				max(spec.a-diffuse.a*2.0, 0.0)); 
+			
+			
+			vec3 refcol = textureCube(environmentMap, env_vec).rgb;
+
+			col = mix(col.rgb, refcol, 
+				envIntensity);  
+		}
+				
+		if (norm.w < 0.5)
+		{
+			col = mix(atmosLighting(col), fullbrightAtmosTransport(col), diffuse.a);
+			col = mix(scaleSoftClip(col), fullbrightScaleSoftClip(col), diffuse.a);
 		}
-	
-		col = atmosLighting(col);
-		col = scaleSoftClip(col);
 
-		col = mix(col.rgb, diffuse.rgb, diffuse.a);
-	}
-	else
-	{
-		col = diffuse.rgb;
+		col = pow(col, vec3(2.2));
+
+		//col = vec3(1,0,1);
+		//col.g = envIntensity;
 	}
 
 	frag_color.rgb = col;
diff --git a/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl b/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl
index c6031fc45a28a184822ff9d1118a2443e8ec76e6..b59fcbe0176e32582efff8bff94401a82b74b98e 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/softenLightV.glsl
@@ -35,6 +35,6 @@ void main()
 	//transform vertex
 	vec4 pos = modelview_projection_matrix * vec4(position.xyz, 1.0);
 	gl_Position = pos; 
-		
+	
 	vary_fragcoord = (pos.xy*0.5+0.5)*screen_res;
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
index cca63872de2142faa13bce99ad2b4e703e1a73bc..1975b18652d29a6c92576b4ceb189e7fc63c33a0 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/spotLightF.glsl
@@ -22,18 +22,15 @@
  * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
  * $/LicenseInfo$
  */
-
  
+#extension GL_ARB_texture_rectangle : enable
+
 #ifdef DEFINE_GL_FRAGCOLOR
 out vec4 frag_color;
 #else
 #define frag_color gl_FragColor
 #endif
 
-//class 1 -- no shadows
-
-#extension GL_ARB_texture_rectangle : enable
-
 uniform sampler2DRect diffuseRect;
 uniform sampler2DRect specularRect;
 uniform sampler2DRect depthMap;
@@ -41,6 +38,7 @@ uniform sampler2DRect normalMap;
 uniform samplerCube environmentMap;
 uniform sampler2D noiseMap;
 uniform sampler2D projectionMap;
+uniform sampler2D lightFunc;
 
 uniform mat4 proj_mat; //screen space to light space
 uniform float proj_near; //near clip for projection
@@ -57,20 +55,59 @@ uniform float far_clip;
 uniform vec3 proj_origin; //origin of projection to be used for angular attenuation
 uniform float sun_wash;
 
+uniform float size;
 uniform vec3 color;
 uniform float falloff;
-uniform float size;
 
-VARYING vec4 vary_fragcoord;
 VARYING vec3 trans_center;
-
+VARYING vec4 vary_fragcoord;
 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);
+	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;
+}
+#endif
+
+vec4 correctWithGamma(vec4 col)
+{
+	return vec4(pow(col.rgb, vec3(2.2)), col.a);
+}
+
 vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
 {
 	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	ret = correctWithGamma(ret);
 	
 	vec2 dist = tc-vec2(0.5);
 	
@@ -86,6 +123,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);
 	
 	vec2 dist = vec2(0.5) - abs(tc-vec2(0.5));
 	
@@ -103,6 +141,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);
 	
 	vec2 dist = tc-vec2(0.5);
 	
@@ -136,15 +175,17 @@ void main()
 	
 	vec3 pos = getPosition(frag.xy).xyz;
 	vec3 lv = trans_center.xyz-pos.xyz;
-	float dist2 = dot(lv,lv);
-	dist2 /= size;
-	if (dist2 > 1.0)
+	float dist = length(lv);
+	dist /= size;
+	if (dist > 1.0)
 	{
 		discard;
 	}
+	
 		
 	vec3 norm = texture2DRect(normalMap, frag.xy).xyz;
-	norm = vec3((norm.xy-0.5)*2.0, norm.z);
+	float envIntensity = norm.z;
+	norm = decode_normal(norm.xy);
 	
 	norm = normalize(norm);
 	float l_dist = -dot(lv, proj_n);
@@ -158,7 +199,10 @@ void main()
 	proj_tc.xyz /= proj_tc.w;
 	
 	float fa = falloff+1.0;
-	float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0);
+	float dist_atten = min(1.0-(dist-1.0*(1.0-fa))/fa, 1.0);
+	dist_atten *= dist_atten;
+	dist_atten *= 2.0;
+
 	if (dist_atten <= 0.0)
 	{
 		discard;
@@ -172,31 +216,35 @@ void main()
 		
 	vec3 diff_tex = texture2DRect(diffuseRect, frag.xy).rgb;
 		
+	vec4 spec = texture2DRect(specularRect, frag.xy);
+
+	
+
 	float noise = texture2D(noiseMap, frag.xy/128.0).b;
+	vec3 dlit = vec3(0, 0, 0);
+	
 	if (proj_tc.z > 0.0 &&
 		proj_tc.x < 1.0 &&
 		proj_tc.y < 1.0 &&
 		proj_tc.x > 0.0 &&
 		proj_tc.y > 0.0)
 	{
-		float lit = 0.0;
 		float amb_da = proj_ambiance;
+		float lit = 0.0;
 		
 		if (da > 0.0)
 		{
+			lit = da * dist_atten * noise;
+
 			float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0);
 			float lod = diff * proj_lod;
 			
 			vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod);
-		
-			vec3 lcol = color.rgb * plcol.rgb * plcol.a;
+			dlit = color.rgb * plcol.rgb * plcol.a;
 			
-			lit = da * dist_atten * noise;
-			
-			col = lcol*lit*diff_tex;
-			amb_da += (da*0.5)*proj_ambiance;
+			col = dlit*lit*diff_tex;
+			//amb_da += (da*0.5)*(1.0-shadow)*proj_ambiance;
 		}
-		
 		//float diff = clamp((proj_range-proj_focus)/proj_range, 0.0, 1.0);
 		vec4 amb_plcol = texture2DLodAmbient(projectionMap, proj_tc.xy, proj_lod);
 							
@@ -205,13 +253,37 @@ void main()
 		amb_da *= dist_atten * noise;
 			
 		amb_da = min(amb_da, 1.0-lit);
-			
-		col += amb_da*color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a;
+		col += amb_da*color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a*diff_tex.rgb;
 	}
 	
-	
-	vec4 spec = texture2DRect(specularRect, frag.xy);
+
 	if (spec.a > 0.0)
+	{
+		dlit *= min(da*6.0, 1.0) * dist_atten;
+		vec3 npos = -normalize(pos);
+
+		//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 += dlit*scol*spec.rgb;
+			//col += spec.rgb;
+		}
+	}	
+
+
+	if (envIntensity > 0.0)
 	{
 		vec3 ref = reflect(normalize(pos), norm);
 		
@@ -229,8 +301,9 @@ void main()
 			{
 				stc.xy /= stc.w;
 
-				float fatten = clamp(spec.a*spec.a+spec.a*0.5, 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 &&
@@ -238,8 +311,7 @@ void main()
 					stc.x > 0.0 &&
 					stc.y > 0.0)
 				{
-					vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
-					col += dist_atten*scol.rgb*color.rgb*scol.a*spec.rgb;
+					col += color.rgb*texture2DLodSpecular(projectionMap, stc.xy, proj_lod-envIntensity*proj_lod).rgb*spec.rgb;										
 				}
 			}
 		}
diff --git a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl
index bac74cbbeff15f0c145434f5343e21908b58588a..6653f57ee17f083f7c56a8a957aa626005c366ea 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/sunLightSSAOF.glsl
@@ -49,6 +49,40 @@ 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);
+	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;
+}
+#endif
+
 vec4 getPosition(vec2 pos_screen)
 {
 	float depth = texture2DRect(depthMap, pos_screen.xy).r;
@@ -123,7 +157,7 @@ void main()
 	vec4 pos = getPosition(pos_screen);
 	
 	vec3 norm = texture2DRect(normalMap, pos_screen).xyz;
-	norm = (norm.xyz-0.5)*2.0; // unpack norm
+	norm = decode_normal(norm.xy);
 		
 	frag_color[0] = 1.0;
 	frag_color[1] = calcAmbientOcclusion(pos, norm);
diff --git a/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl
index daf1cc7ea202bc89b7338f90e84647c1f2c400b3..52a429465f31ab6cffb837ffa9f0ff23d0de06b3 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/terrainF.glsl
@@ -39,6 +39,12 @@ VARYING vec3 vary_normal;
 VARYING vec4 vary_texcoord0;
 VARYING vec4 vary_texcoord1;
 
+vec2 encode_normal(vec3 n)
+{
+	float f = sqrt(8 * n.z + 8);
+	return n.xy / f + 0.5;
+}
+
 void main()
 {
 	/// Note: This should duplicate the blending functionality currently used for the terrain rendering.
@@ -56,6 +62,6 @@ void main()
 	frag_data[0] = vec4(outColor.rgb, 0.0);
 	frag_data[1] = vec4(0,0,0,0);
 	vec3 nvn = normalize(vary_normal);
-	frag_data[2] = vec4(nvn.xyz * 0.5 + 0.5, 0.0);
+	frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, 0.0);
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl
index da253846efc42eaa4f004dae2ea91d1bda188f0f..808750496f96e62263130f173814bf4530c1790b 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/treeF.glsl
@@ -37,6 +37,12 @@ VARYING vec2 vary_texcoord0;
 
 uniform float minimum_alpha;
 
+vec2 encode_normal(vec3 n)
+{
+	float f = sqrt(8 * n.z + 8);
+	return n.xy / f + 0.5;
+}
+
 void main() 
 {
 	vec4 col = texture2D(diffuseMap, vary_texcoord0.xy);
@@ -48,5 +54,5 @@ void main()
 	frag_data[0] = vec4(vertex_color.rgb*col.rgb, 0.0);
 	frag_data[1] = vec4(0,0,0,0);
 	vec3 nvn = normalize(vary_normal);
-	frag_data[2] = vec4(nvn.xyz * 0.5 + 0.5, 0.0);
+	frag_data[2] = vec4(encode_normal(nvn.xyz), 0.0, 0.0);
 }
diff --git a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
index 1ae006bc8aa6b92277036ac54bbed9df4ca0ba23..daa2fb390adb3ae4cd58689a9482ef93912ae2b3 100755
--- a/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/deferred/waterF.glsl
@@ -67,6 +67,12 @@ VARYING vec4 littleWave;
 VARYING vec4 view;
 VARYING vec4 vary_position;
 
+vec2 encode_normal(vec3 n)
+{
+	float f = sqrt(8 * n.z + 8);
+	return n.xy / f + 0.5;
+}
+
 void main() 
 {
 	vec4 color;
@@ -161,5 +167,5 @@ void main()
 	
 	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(screenspacewavef.xyz*0.5+0.5, screenspacewavef.z*0.5); // normalxyz, displace
+	frag_data[2] = vec4(encode_normal(screenspacewavef), 0.0, 0.0); // normalxyz, displace
 }
diff --git a/indra/newview/app_settings/shaders/class1/environment/waterV.glsl b/indra/newview/app_settings/shaders/class1/environment/waterV.glsl
index 5aff156eae64d611078b22a71824960c29666068..352cea7aaabcee7dc2e79aeaae496d99ba53fcf1 100755
--- a/indra/newview/app_settings/shaders/class1/environment/waterV.glsl
+++ b/indra/newview/app_settings/shaders/class1/environment/waterV.glsl
@@ -82,7 +82,8 @@ 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
new file mode 100644
index 0000000000000000000000000000000000000000..6523a06d22b6259945e24251c7c8b73fecfba192
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/downsampleDepthF.glsl
@@ -0,0 +1,67 @@
+/** 
+ * @file debugF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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_color;
+#else
+#define frag_color gl_FragColor
+#endif
+
+uniform sampler2D depthMap;
+
+uniform float delta;
+
+VARYING vec2 tc0;
+VARYING vec2 tc1;
+VARYING vec2 tc2;
+VARYING vec2 tc3;
+VARYING vec2 tc4;
+VARYING vec2 tc5;
+VARYING vec2 tc6;
+VARYING vec2 tc7;
+VARYING vec2 tc8;
+
+void main() 
+{
+	vec4 depth1 = 
+		vec4(texture2D(depthMap, tc0).r,
+			texture2D(depthMap, tc1).r,
+			texture2D(depthMap, tc2).r,
+			texture2D(depthMap, tc3).r);
+
+	vec4 depth2 = 
+		vec4(texture2D(depthMap, tc4).r,
+			texture2D(depthMap, tc5).r,
+			texture2D(depthMap, tc6).r,
+			texture2D(depthMap, tc7).r);
+
+	depth1 = min(depth1, depth2);
+	float depth = min(depth1.x, depth1.y);
+	depth = min(depth, depth1.z);
+	depth = min(depth, depth1.w);
+	depth = min(depth, texture2D(depthMap, tc8).r);
+
+	gl_FragDepth = depth;
+}
diff --git a/indra/newview/app_settings/shaders/class1/interface/downsampleDepthRectF.glsl b/indra/newview/app_settings/shaders/class1/interface/downsampleDepthRectF.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..0e5dc0818363afffa65038762f0ca726ce3d7069
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/downsampleDepthRectF.glsl
@@ -0,0 +1,69 @@
+/** 
+ * @file debugF.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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$
+ */
+
+#extension GL_ARB_texture_rectangle : enable
+
+#ifdef DEFINE_GL_FRAGCOLOR
+out vec4 frag_color;
+#else
+#define frag_color gl_FragColor
+#endif
+
+uniform sampler2DRect depthMap;
+
+uniform float delta;
+
+VARYING vec2 tc0;
+VARYING vec2 tc1;
+VARYING vec2 tc2;
+VARYING vec2 tc3;
+VARYING vec2 tc4;
+VARYING vec2 tc5;
+VARYING vec2 tc6;
+VARYING vec2 tc7;
+VARYING vec2 tc8;
+
+void main() 
+{
+	vec4 depth1 = 
+		vec4(texture2DRect(depthMap, tc0).r,
+			texture2DRect(depthMap, tc1).r,
+			texture2DRect(depthMap, tc2).r,
+			texture2DRect(depthMap, tc3).r);
+
+	vec4 depth2 = 
+		vec4(texture2DRect(depthMap, tc4).r,
+			texture2DRect(depthMap, tc5).r,
+			texture2DRect(depthMap, tc6).r,
+			texture2DRect(depthMap, tc7).r);
+
+	depth1 = min(depth1, depth2);
+	float depth = min(depth1.x, depth1.y);
+	depth = min(depth, depth1.z);
+	depth = min(depth, depth1.w);
+	depth = min(depth, texture2DRect(depthMap, tc8).r);
+
+	gl_FragDepth = depth;
+}
diff --git a/indra/newview/app_settings/shaders/class1/interface/downsampleDepthV.glsl b/indra/newview/app_settings/shaders/class1/interface/downsampleDepthV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..71d80911d62635c28e5996fd174800fc476a4c8d
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/downsampleDepthV.glsl
@@ -0,0 +1,59 @@
+/** 
+ * @file debugV.glsl
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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 mat4 modelview_projection_matrix;
+
+ATTRIBUTE vec3 position;
+
+uniform vec2 screen_res;
+
+uniform vec2 delta;
+
+VARYING vec2 tc0;
+VARYING vec2 tc1;
+VARYING vec2 tc2;
+VARYING vec2 tc3;
+VARYING vec2 tc4;
+VARYING vec2 tc5;
+VARYING vec2 tc6;
+VARYING vec2 tc7;
+VARYING vec2 tc8;
+
+void main()
+{
+	gl_Position = vec4(position, 1.0); 
+	
+	vec2 tc = (position.xy*0.5+0.5)*screen_res;
+	tc0 = tc+vec2(-delta.x,-delta.y);
+	tc1 = tc+vec2(0,-delta.y);
+	tc2 = tc+vec2(delta.x,-delta.y);
+	tc3 = tc+vec2(-delta.x,0);
+	tc4 = tc+vec2(0,0);
+	tc5 = tc+vec2(delta.x,0);
+	tc6 = tc+vec2(-delta.x,delta.y);
+	tc7 = tc+vec2(0,delta.y);
+	tc8 = tc+vec2(delta.x,delta.y);
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/interface/highlightNormV.glsl b/indra/newview/app_settings/shaders/class1/interface/highlightNormV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..947c2b00652b7ba3c602212d1a728f0c036b57e2
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/highlightNormV.glsl
@@ -0,0 +1,42 @@
+/** 
+ * @file highlightV.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 mat4 texture_matrix0;
+uniform mat4 modelview_projection_matrix;
+
+ATTRIBUTE vec3 position;
+ATTRIBUTE vec2 texcoord0;
+ATTRIBUTE vec2 texcoord1;
+ATTRIBUTE vec2 texcoord2;
+
+VARYING vec2 vary_texcoord0;
+
+void main()
+{
+	//transform vertex
+	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
+	vary_texcoord0 = (texture_matrix0 * vec4(texcoord1,0,1)).xy;
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/interface/highlightSpecV.glsl b/indra/newview/app_settings/shaders/class1/interface/highlightSpecV.glsl
new file mode 100644
index 0000000000000000000000000000000000000000..c5d102b7392c65b844382595447d95eb921a3d85
--- /dev/null
+++ b/indra/newview/app_settings/shaders/class1/interface/highlightSpecV.glsl
@@ -0,0 +1,42 @@
+/** 
+ * @file highlightV.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 mat4 texture_matrix0;
+uniform mat4 modelview_projection_matrix;
+
+ATTRIBUTE vec3 position;
+ATTRIBUTE vec2 texcoord0;
+ATTRIBUTE vec2 texcoord1;
+ATTRIBUTE vec2 texcoord2;
+
+VARYING vec2 vary_texcoord0;
+
+void main()
+{
+	//transform vertex
+	gl_Position = modelview_projection_matrix * vec4(position.xyz, 1.0);
+	vary_texcoord0 = (texture_matrix0 * vec4(texcoord2,0,1)).xy;
+}
+
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskF.glsl
index cf29939cb2353637e33f43c1548d083bfd6bcf64..eaaa7b208d78773f996106c197687705d936d3fe 100755
--- a/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskF.glsl
@@ -39,13 +39,15 @@ VARYING vec2 vary_texcoord0;
 
 void default_lighting() 
 {
-	vec4 color = diffuseLookup(vary_texcoord0.xy) * vertex_color;
+	vec4 color = diffuseLookup(vary_texcoord0.xy);
 	
 	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/class1/lighting/lightAlphaMaskNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskNonIndexedF.glsl
index 4070d41f47860b077e36a96cc56809a64565dd4d..b9ddbc8e1ce1786bcd49e4872d9af71cb35c5d5f 100755
--- a/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskNonIndexedF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightAlphaMaskNonIndexedF.glsl
@@ -41,13 +41,15 @@ VARYING vec2 vary_texcoord0;
 
 void default_lighting() 
 {
-	vec4 color = texture2D(diffuseMap,vary_texcoord0.xy) * vertex_color;
+	vec4 color = texture2D(diffuseMap,vary_texcoord0.xy);
 
 	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/class1/lighting/lightFullbrightAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightAlphaMaskF.glsl
index 6c34643aab0e577d00242b5942908b32e8efe70d..5740987ab1cdbfcfe95abab93b53e90e4687c6fc 100755
--- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightAlphaMaskF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightAlphaMaskF.glsl
@@ -30,6 +30,7 @@ out vec4 frag_color;
 #endif
 
 uniform float minimum_alpha;
+uniform float texture_gamma;
 
 vec3 fullbrightAtmosTransport(vec3 light);
 vec3 fullbrightScaleSoftClip(vec3 light);
@@ -39,13 +40,16 @@ VARYING vec2 vary_texcoord0;
 
 void fullbright_lighting()
 {
-	vec4 color = diffuseLookup(vary_texcoord0.xy) * vertex_color;
+	vec4 color = diffuseLookup(vary_texcoord0.xy);
 	
 	if (color.a < minimum_alpha)
 	{
 		discard;
 	}
 
+	color.rgb *= vertex_color.rgb;
+
+	color.rgb = pow(color.rgb, vec3(texture_gamma));
 	color.rgb = fullbrightAtmosTransport(color.rgb);
 	
 	color.rgb = fullbrightScaleSoftClip(color.rgb);
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl
index 2ff7f795b05e88bcb470a8a2b212813671efeaa2..c8771a3f1eac8e728eb1a4df67de179d1ee889fd 100755
--- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightF.glsl
@@ -32,6 +32,8 @@ out vec4 frag_color;
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
 
+uniform float texture_gamma;
+
 vec3 fullbrightAtmosTransport(vec3 light);
 vec3 fullbrightScaleSoftClip(vec3 light);
 
@@ -39,10 +41,14 @@ void fullbright_lighting()
 {
 	vec4 color = diffuseLookup(vary_texcoord0.xy) * vertex_color;
 	
+	color.rgb = pow(color.rgb, vec3(texture_gamma));
+
 	color.rgb = fullbrightAtmosTransport(color.rgb);
 	
 	color.rgb = fullbrightScaleSoftClip(color.rgb);
 
+	color.rgb = pow(color.rgb, vec3(1.0/texture_gamma));
+
 	frag_color = color;
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightNonIndexedAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightNonIndexedAlphaMaskF.glsl
index f4477bd29ac021a89cb544b433047c851269912b..f72f20b03d754dc13c4fff8447e50df1910f333c 100755
--- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightNonIndexedAlphaMaskF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightNonIndexedAlphaMaskF.glsl
@@ -30,6 +30,7 @@ out vec4 frag_color;
 #endif
 
 uniform float minimum_alpha;
+uniform float texture_gamma;
 
 vec3 fullbrightAtmosTransport(vec3 light);
 vec3 fullbrightScaleSoftClip(vec3 light);
@@ -41,17 +42,22 @@ VARYING vec2 vary_texcoord0;
 
 void fullbright_lighting()
 {
-	vec4 color = texture2D(diffuseMap,vary_texcoord0.xy) * vertex_color;
+	vec4 color = texture2D(diffuseMap,vary_texcoord0.xy);
 	
 	if (color.a < minimum_alpha)
 	{
 		discard;
 	}
+	
+	color.rgb *= vertex_color.rgb;
 
+	color.rgb = pow(color.rgb, vec3(texture_gamma));
 	color.rgb = fullbrightAtmosTransport(color.rgb);
 	
 	color.rgb = fullbrightScaleSoftClip(color.rgb);
 
+	color.rgb = pow(color.rgb, vec3(1.0/texture_gamma));
+
 	frag_color = color;
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl
index 777c8b45bb3ffe2653e0a0415949d3c8b579ad52..c8282e9a51eafe3a7859e798ccdca204be3208c7 100755
--- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyF.glsl
@@ -50,7 +50,7 @@ void fullbright_shiny_lighting()
 
 	color.rgb = fullbrightScaleSoftClip(color.rgb);
 
-	color.a = max(color.a, vertex_color.a);
+	color.a = 1.0;
 
 	frag_color = color;
 }
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyNonIndexedF.glsl
index 4fa3b1d939cda3cdcfc7e32a60504788db1dff85..e7dbd4bbd2d3954c0b5cfd90659cd79b8c4bcb68 100755
--- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyNonIndexedF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyNonIndexedF.glsl
@@ -51,7 +51,7 @@ void fullbright_shiny_lighting()
 
 	color.rgb = fullbrightScaleSoftClip(color.rgb);
 
-	color.a = max(color.a, vertex_color.a);
+	color.a = 1.0;
 
 	frag_color = color;
 }
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterF.glsl
index 58984a42631e33d3e83795e13b3e66756501a81d..5886fc65bea8ec8adc90857756419a1906893dab 100755
--- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterF.glsl
@@ -48,7 +48,7 @@ void fullbright_shiny_lighting_water()
 
 	color.rgb = fullbrightShinyAtmosTransport(color.rgb);
 	color.rgb = fullbrightScaleSoftClip(color.rgb);
-	color.a = max(color.a, vertex_color.a);
+	color.a = 1.0;
 
 	frag_color = applyWaterFog(color);
 }
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterNonIndexedF.glsl
index a39b7205d79b6a3208c4c4a52ef935a0d3a4d62f..cddc7d8df80f05e0b4fe2c507b49f4bcbf3e0331 100755
--- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterNonIndexedF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightShinyWaterNonIndexedF.glsl
@@ -49,7 +49,7 @@ void fullbright_shiny_lighting_water()
 
 	color.rgb = fullbrightShinyAtmosTransport(color.rgb);
 	color.rgb = fullbrightScaleSoftClip(color.rgb);
-	color.a = max(color.a, vertex_color.a);
+	color.a = 1.0;
 
 	frag_color = applyWaterFog(color);
 }
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl
index 9c82056fd7f71dda504eeb247ace58338bc2c7ff..6dd3bb937f175f72748fbe8848881a44e78649cf 100755
--- a/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightFullbrightWaterAlphaMaskF.glsl
@@ -41,7 +41,9 @@ VARYING vec2 vary_texcoord0;
 
 void fullbright_lighting_water()
 {
-	vec4 color = diffuseLookup(vary_texcoord0.xy) * vertex_color;
+	vec4 color = diffuseLookup(vary_texcoord0.xy);
+
+	color.rgb *= vertex_color.rgb;
 
 	if (color.a < minimum_alpha)
 	{
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl
index 52e3b2ad026f0df5da4465bb55662fe302f751ea..9208c148efa48a76d34ea5781b30917e33a7a4ef 100755
--- a/indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightShinyF.glsl
@@ -50,7 +50,7 @@ void shiny_lighting()
 	color.rgb = atmosLighting(color.rgb);
 
 	color.rgb = scaleSoftClip(color.rgb);
-	color.a = max(color.a, vertex_color.a);
+	color.a = 1.0;
 	frag_color = color;
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightShinyNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightShinyNonIndexedF.glsl
index 474d5ea4969d4e22f73dec43e343cd009b17cc14..92628faa68a64b8da9b6fed87fafeb109039964c 100755
--- a/indra/newview/app_settings/shaders/class1/lighting/lightShinyNonIndexedF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightShinyNonIndexedF.glsl
@@ -51,7 +51,7 @@ void shiny_lighting()
 	color.rgb = atmosLighting(color.rgb);
 
 	color.rgb = scaleSoftClip(color.rgb);
-	color.a = max(color.a, vertex_color.a);
+	color.a = 1.0;
 	frag_color = color;
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl
index d2a4c47aac526b10d2fbe95a04a66e8b3f7d8f2e..61841674e211ad2718a3f7bd83e894d877838337 100755
--- a/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterF.glsl
@@ -47,7 +47,7 @@ void shiny_lighting_water()
 	color.rgb = mix(color.rgb, envColor.rgb, vertex_color.a);
 
 	color.rgb = atmosLighting(color.rgb);
-	color.a = max(color.a, vertex_color.a);
+	color.a = 1.0;
 	frag_color = applyWaterFog(color);
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterNonIndexedF.glsl
index f3bd66236449ad872a38f78ff44201d5deb8e1cd..0b6e835fd06659e66fd35b529e244dda2bb2d6c4 100755
--- a/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterNonIndexedF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightShinyWaterNonIndexedF.glsl
@@ -48,7 +48,7 @@ void shiny_lighting_water()
 	color.rgb = mix(color.rgb, envColor.rgb, vertex_color.a);
 
 	color.rgb = atmosLighting(color.rgb);
-	color.a = max(color.a, vertex_color.a);
+	color.a = 1.0;
 	frag_color = applyWaterFog(color);
 }
 
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl
index b68240ba0d6e13ebea4c2fdfeb47f38ba2f39cf2..3426fea52fa2e2023f8465539541c4a29e27730b 100755
--- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskF.glsl
@@ -39,7 +39,9 @@ VARYING vec2 vary_texcoord0;
 
 void default_lighting_water()
 {
-	vec4 color = diffuseLookup(vary_texcoord0.xy) * vertex_color;
+	vec4 color = diffuseLookup(vary_texcoord0.xy);
+
+	color.rgb *= vertex_color.rgb;
 
 	if (color.a < minimum_alpha)
 	{
diff --git a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl b/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl
index da3b20012d850323fbaad0e5e3affae5d1936a5c..d9faa9b314273dbda5c177279df800dbc55a5ded 100755
--- a/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl
+++ b/indra/newview/app_settings/shaders/class1/lighting/lightWaterAlphaMaskNonIndexedF.glsl
@@ -41,7 +41,9 @@ VARYING vec2 vary_texcoord0;
 
 void default_lighting_water()
 {
-	vec4 color = texture2D(diffuseMap,vary_texcoord0.xy) * vertex_color;
+	vec4 color = texture2D(diffuseMap,vary_texcoord0.xy);
+
+	color.rgb *= vertex_color.rgb;
 
 	if (color.a < minimum_alpha)
 	{
diff --git a/indra/newview/app_settings/shaders/class1/objects/emissiveSkinnedV.glsl b/indra/newview/app_settings/shaders/class1/objects/emissiveSkinnedV.glsl
index 8494ffba5289f7f3c06d74387d6cff315417b77e..90649041917c1ffdc64a441ae9dc30fb9c2e2197 100755
--- a/indra/newview/app_settings/shaders/class1/objects/emissiveSkinnedV.glsl
+++ b/indra/newview/app_settings/shaders/class1/objects/emissiveSkinnedV.glsl
@@ -48,11 +48,9 @@ void main()
 	mat = modelview_matrix * mat;
 	vec3 pos = (mat*vec4(position.xyz, 1.0)).xyz;
 	
+	vertex_color = emissive;
+
 	calcAtmospherics(pos.xyz);
 
-	vertex_color = emissive;
-	
 	gl_Position = projection_matrix*vec4(pos, 1.0);
-		
-	
 }
diff --git a/indra/newview/app_settings/shaders/class1/transform/binormalV.glsl b/indra/newview/app_settings/shaders/class1/transform/binormalV.glsl
index 44f1aa34a0313f0451b26df3c6a78afd8dbb2364..449d8d8b4e392dee46508084365e9a1df0c2b9f4 100755
--- a/indra/newview/app_settings/shaders/class1/transform/binormalV.glsl
+++ b/indra/newview/app_settings/shaders/class1/transform/binormalV.glsl
@@ -25,12 +25,12 @@
 
 uniform mat3 normal_matrix;
 
-ATTRIBUTE vec3 binormal;
+ATTRIBUTE vec4 tangent;
 
-VARYING vec4 binormal_out;
+VARYING vec4 tangent_out;
 
 void main()
 {
-	binormal_out = vec4(normal_matrix * binormal, 0.0);
+	tangent_out = vec4(normal_matrix * tangent.xyz), tangent.w);
 }
 
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
deleted file mode 100755
index 12706f130bd479e25c9facadf566577a99f5209e..0000000000000000000000000000000000000000
--- a/indra/newview/app_settings/shaders/class2/deferred/alphaF.glsl
+++ /dev/null
@@ -1,164 +0,0 @@
-/** 
- * @file alphaF.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$
- */
-
-#extension GL_ARB_texture_rectangle : enable
-
-#ifdef DEFINE_GL_FRAGCOLOR
-out vec4 frag_color;
-#else
-#define frag_color gl_FragColor
-#endif
-
-VARYING vec4 vertex_color;
-VARYING vec2 vary_texcoord0;
-
-uniform sampler2DShadow shadowMap0;
-uniform sampler2DShadow shadowMap1;
-uniform sampler2DShadow shadowMap2;
-uniform sampler2DShadow shadowMap3;
-uniform sampler2DRect depthMap;
-
-uniform mat4 shadow_matrix[6];
-uniform vec4 shadow_clip;
-uniform vec2 screen_res;
-uniform vec2 shadow_res;
-
-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;
-
-uniform float shadow_bias;
-
-uniform mat4 inv_proj;
-
-float pcfShadow(sampler2DShadow shadowMap, vec4 stc)
-{
-	stc.xyz /= stc.w;
-	stc.z += shadow_bias;
-		
-	stc.x = floor(stc.x*shadow_res.x + fract(stc.y*shadow_res.y*12345))/shadow_res.x; // add some chaotic jitter to X sample pos according to Y to disguise the snapping going on here
-	
-	float cs = shadow2D(shadowMap, stc.xyz).x;
-	float shadow = cs;
-	
-    shadow += shadow2D(shadowMap, stc.xyz+vec3(2.0/shadow_res.x, 1.5/shadow_res.y, 0.0)).x;
-    shadow += shadow2D(shadowMap, stc.xyz+vec3(1.0/shadow_res.x, -1.5/shadow_res.y, 0.0)).x;
-    shadow += shadow2D(shadowMap, stc.xyz+vec3(-1.0/shadow_res.x, 1.5/shadow_res.y, 0.0)).x;
-    shadow += shadow2D(shadowMap, stc.xyz+vec3(-2.0/shadow_res.x, -1.5/shadow_res.y, 0.0)).x;
-                       
-    return shadow*0.2;
-}
-
-
-void main() 
-{
-	vec2 frag = vary_fragcoord.xy/vary_fragcoord.z*0.5+0.5;
-	frag *= screen_res;
-	
-	float shadow = 0.0;
-	vec4 pos = vec4(vary_position, 1.0);
-	
-	vec4 spos = pos;
-		
-	if (spos.z > -shadow_clip.w)
-	{	
-		vec4 lpos;
-		
-		vec4 near_split = shadow_clip*-0.75;
-		vec4 far_split = shadow_clip*-1.25;
-		vec4 transition_domain = near_split-far_split;
-		float weight = 0.0;
-
-		if (spos.z < near_split.z)
-		{
-			lpos = shadow_matrix[3]*spos;
-			
-			float w = 1.0;
-			w -= max(spos.z-far_split.z, 0.0)/transition_domain.z;
-			shadow += pcfShadow(shadowMap3, lpos)*w;
-			weight += w;
-			shadow += max((pos.z+shadow_clip.z)/(shadow_clip.z-shadow_clip.w)*2.0-1.0, 0.0);
-		}
-
-		if (spos.z < near_split.y && spos.z > far_split.z)
-		{
-			lpos = shadow_matrix[2]*spos;
-			
-			float w = 1.0;
-			w -= max(spos.z-far_split.y, 0.0)/transition_domain.y;
-			w -= max(near_split.z-spos.z, 0.0)/transition_domain.z;
-			shadow += pcfShadow(shadowMap2, lpos)*w;
-			weight += w;
-		}
-
-		if (spos.z < near_split.x && spos.z > far_split.y)
-		{
-			lpos = shadow_matrix[1]*spos;
-			
-			float w = 1.0;
-			w -= max(spos.z-far_split.x, 0.0)/transition_domain.x;
-			w -= max(near_split.y-spos.z, 0.0)/transition_domain.y;
-			shadow += pcfShadow(shadowMap1, lpos)*w;
-			weight += w;
-		}
-
-		if (spos.z > far_split.x)
-		{
-			lpos = shadow_matrix[0]*spos;
-							
-			float w = 1.0;
-			w -= max(near_split.x-spos.z, 0.0)/transition_domain.x;
-				
-			shadow += pcfShadow(shadowMap0, lpos)*w;
-			weight += w;
-		}
-		
-
-		shadow /= weight;
-	}
-	else
-	{
-		shadow = 1.0;
-	}
-	
-	vec4 diff = diffuseLookup(vary_texcoord0.xy);
-
-	vec4 col = vec4(vary_ambient + vary_directional.rgb*shadow, vertex_color.a);
-	vec4 color = diff * col;
-	
-	color.rgb = atmosLighting(color.rgb);
-
-	color.rgb = scaleSoftClip(color.rgb);
-
-	color.rgb += diff.rgb * vary_pointlight_col.rgb;
-
-	frag_color = color;
-}
-
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedF.glsl
index 228dc104ac05c2b8fa7774328d388b55652d383b..9670d593996286f1cfa749b88943a68663adadb7 100755
--- a/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedF.glsl
@@ -52,12 +52,54 @@ VARYING vec3 vary_position;
 VARYING vec3 vary_pointlight_col;
 VARYING vec2 vary_texcoord0;
 VARYING vec4 vertex_color;
+VARYING vec3 vary_norm;
 
 uniform vec2 shadow_res;
 uniform float shadow_bias;
 
 uniform mat4 inv_proj;
 
+uniform vec4 light_position[8];
+uniform vec3 light_direction[8];
+uniform vec3 light_attenuation[8]; 
+uniform vec3 light_diffuse[8];
+
+vec3 calcDirectionalLight(vec3 n, vec3 l)
+{
+        float a = pow(max(dot(n,l),0.0), 0.7);
+        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(pow(dot(n, lv), 0.7), 0.0);		
+	}
+
+	return vec3(da,da,da);	
+}
+
 vec4 getPosition(vec2 pos_screen)
 {
 	float depth = texture2DRect(depthMap, pos_screen.xy).a;
@@ -161,17 +203,32 @@ void main()
 	{
 		shadow = 1.0;
 	}
-
+	vec3 n = vary_norm;
+	vec3 l = light_position[0].xyz;
+	vec3 dlight = calcDirectionalLight(n, l);
+	dlight = dlight * vary_directional.rgb * vary_pointlight_col;
 	vec4 diff = texture2D(diffuseMap,vary_texcoord0.xy);
 
-	vec4 col = vec4(vary_ambient + vary_directional.rgb*shadow, vertex_color.a);
+	vec4 col = vec4(vary_ambient + dlight*shadow, vertex_color.a);
 	vec4 color = diff * col;
 	
 	color.rgb = atmosLighting(color.rgb);
 
 	color.rgb = scaleSoftClip(color.rgb);
+	vec3 light_col = vec3(0,0,0);
+
+  #define LIGHT_LOOP(i) \
+		light_col += light_diffuse[i].rgb * calcPointLightOrSpotLight(pos.xyz, vary_norm, light_position[i], light_direction[i], light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z);
+
+	LIGHT_LOOP(1)
+	LIGHT_LOOP(2)
+	LIGHT_LOOP(3)
+	LIGHT_LOOP(4)
+	LIGHT_LOOP(5)
+	LIGHT_LOOP(6)
+	LIGHT_LOOP(7)
 
-	color.rgb += diff.rgb * vary_pointlight_col.rgb;
+	color.rgb += diff.rgb * vary_pointlight_col * light_col;
 
 	frag_color = color;	
 }
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedNoColorF.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedNoColorF.glsl
index c3950a10e17ef8e3d3ee0e6472a724d3c1486de2..fae279fba059578e1cd6b2e0bc2c07852fb94212 100755
--- a/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedNoColorF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaNonIndexedNoColorF.glsl
@@ -53,6 +53,7 @@ VARYING vec3 vary_fragcoord;
 VARYING vec3 vary_position;
 VARYING vec3 vary_pointlight_col;
 VARYING vec2 vary_texcoord0;
+VARYING vec3 vary_norm;
 
 uniform vec2 shadow_res;
 
@@ -60,6 +61,47 @@ uniform float shadow_bias;
 
 uniform mat4 inv_proj;
 
+uniform vec4 light_position[8];
+uniform vec3 light_direction[8];
+uniform vec3 light_attenuation[8]; 
+uniform vec3 light_diffuse[8];
+
+vec3 calcDirectionalLight(vec3 n, vec3 l)
+{
+        float a = pow(max(dot(n,l),0.0), 0.7);
+        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(pow(dot(n, lv), 0.7), 0.0);		
+	}
+
+	return vec3(da,da,da);	
+}
+
 vec4 getPosition(vec2 pos_screen)
 {
 	float depth = texture2DRect(depthMap, pos_screen.xy).a;
@@ -169,15 +211,31 @@ void main()
 	{
 		shadow = 1.0;
 	}
+	vec3 n = vary_norm;
+	vec3 l = light_position[0].xyz;
+	vec3 dlight = calcDirectionalLight(n, l);
+	dlight = dlight * vary_directional.rgb * vary_pointlight_col;
 	
-	vec4 col = vec4(vary_ambient + vary_directional.rgb*shadow, 1.0);
+	vec4 col = vec4(vary_ambient + dlight*shadow, 1.0);
 	vec4 color = diff * col;
 	
 	color.rgb = atmosLighting(color.rgb);
 
 	color.rgb = scaleSoftClip(color.rgb);
+	vec3 light_col = vec3(0,0,0);
+
+  #define LIGHT_LOOP(i) \
+		light_col += light_diffuse[i].rgb * calcPointLightOrSpotLight(pos.xyz, vary_norm, light_position[i], light_direction[i], light_attenuation[i].x, light_attenuation[i].y, light_attenuation[i].z);
+
+	LIGHT_LOOP(1)
+	LIGHT_LOOP(2)
+	LIGHT_LOOP(3)
+	LIGHT_LOOP(4)
+	LIGHT_LOOP(5)
+	LIGHT_LOOP(6)
+	LIGHT_LOOP(7)
 
-	color.rgb += diff.rgb * vary_pointlight_col.rgb;
+	color.rgb += diff.rgb * vary_pointlight_col * light_col;
 
 	frag_color = color;
 }
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaSkinnedV.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaSkinnedV.glsl
index 9629cfe824e6f312755be7bd07b8ab7ee567efa4..7f4d82ecc6a302dc3d2b9b57dc770b8705b9649d 100755
--- a/indra/newview/app_settings/shaders/class2/deferred/alphaSkinnedV.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaSkinnedV.glsl
@@ -50,7 +50,7 @@ VARYING vec3 vary_pointlight_col;
 
 VARYING vec4 vertex_color;
 VARYING vec2 vary_texcoord0;
-
+VARYING vec3 vary_norm;
 
 uniform float near_clip;
 uniform float shadow_offset;
@@ -115,7 +115,8 @@ void main()
 	n.xyz = normalize(n.xyz-pos.xyz);
 	
 	vec3 norm = n.xyz;
-	
+	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;
 			
diff --git a/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl b/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl
index 1586aab0f25587cd34ae815f330535af4d8b0f1c..13c6ffc607c323c78ca08f6651e71c8ff026a3cf 100755
--- a/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/alphaV.glsl
@@ -25,19 +25,36 @@
 
 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);
 
-float calcDirectionalLight(vec3 n, vec3 l);
+vec3 calcDirectionalLight(vec3 n, vec3 l);
 
 vec3 atmosAmbient(vec3 light);
 vec3 atmosAffectDirectionalLight(float lightIntensity);
@@ -50,9 +67,12 @@ VARYING vec3 vary_fragcoord;
 VARYING vec3 vary_position;
 VARYING vec3 vary_pointlight_col;
 
+#ifdef USE_VERTEX_COLOR
 VARYING vec4 vertex_color;
-VARYING vec2 vary_texcoord0;
+#endif
 
+VARYING vec2 vary_texcoord0;
+VARYING vec3 vary_norm;
 
 uniform float near_clip;
 uniform float shadow_offset;
@@ -63,13 +83,15 @@ uniform vec3 light_direction[8];
 uniform vec3 light_attenuation[8]; 
 uniform vec3 light_diffuse[8];
 
-float calcDirectionalLight(vec3 n, vec3 l)
+uniform vec3 sun_dir;
+
+vec3 calcDirectionalLight(vec3 n, vec3 l)
 {
         float a = max(dot(n,l),0.0);
-        return a;
+        return vec3(a,a,a);
 }
 
-float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, float fa, float is_pointlight)
+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;
@@ -96,55 +118,107 @@ float calcPointLightOrSpotLight(vec3 v, vec3 n, vec4 lp, vec3 ln, float la, floa
 		da *= max(dot(n, lv), 0.0);		
 	}
 
-	return da;	
+	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);
-	passTextureIndex();
-	vec4 pos = (modelview_matrix * vert);
+	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;
-		
-	vec3 norm = normalize(normal_matrix * normal);
+#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);
 
-	
-	// Collect normal lights
-	col.rgb += light_diffuse[2].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[2], light_direction[2], light_attenuation[2].x, light_attenuation[2].y, light_attenuation[2].z);
-	col.rgb += light_diffuse[3].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[3], light_direction[3], light_attenuation[3].x, light_attenuation[3].y, light_attenuation[3].z);
-	col.rgb += light_diffuse[4].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[4], light_direction[4], light_attenuation[4].x, light_attenuation[4].y, light_attenuation[4].z);
-	col.rgb += light_diffuse[5].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[5], light_direction[5], light_attenuation[5].x, light_attenuation[5].y, light_attenuation[5].z);
-	col.rgb += light_diffuse[6].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[6], light_direction[6], light_attenuation[6].x, light_attenuation[6].y, light_attenuation[6].z);
-	col.rgb += light_diffuse[7].rgb*calcPointLightOrSpotLight(pos.xyz, norm, light_position[7], light_direction[7], light_attenuation[7].x, light_attenuation[7].y, light_attenuation[7].z);
+	vec3 dff = pow(diffuse_color.rgb, vec3(2.2f,2.2f,2.2f));
 
-	vary_pointlight_col = col.rgb*diffuse_color.rgb;
+	vary_pointlight_col = dff;
 
 	col.rgb = vec3(0,0,0);
 
 	// Add windlight lights
-	col.rgb = atmosAmbient(vec3(0.));
+	col.rgb = atmosAmbient(col.rgb);
 	
-	vary_ambient = col.rgb*diffuse_color.rgb;
-	vary_directional.rgb = diffuse_color.rgb*atmosAffectDirectionalLight(max(calcDirectionalLight(norm, light_position[0].xyz), (1.0-diffuse_color.a)*(1.0-diffuse_color.a)));
+	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*diffuse_color.rgb;
+	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 5621e47ab70989761a7d7249fb43edb503c7b8a6..780df9ed1ac8c0a40ff9231b32af7f39bf09d988 100755
--- a/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/multiSpotLightF.glsl
@@ -39,6 +39,7 @@ uniform samplerCube environmentMap;
 uniform sampler2DRect lightMap;
 uniform sampler2D noiseMap;
 uniform sampler2D projectionMap;
+uniform sampler2D lightFunc;
 
 uniform mat4 proj_mat; //screen space to light space
 uniform float proj_near; //near clip for projection
@@ -67,10 +68,51 @@ 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);
+	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;
+}
+#endif
+
+vec4 correctWithGamma(vec4 col)
+{
+	return vec4(pow(col.rgb, vec3(2.2)), col.a);
+}
+
+
 vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
 {
 	vec4 ret = texture2DLod(projectionMap, tc, lod);
-	
+	ret = correctWithGamma(ret);
+
 	vec2 dist = tc-vec2(0.5);
 	
 	float det = max(1.0-lod/(proj_lod*0.5), 0.0);
@@ -85,7 +127,8 @@ 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);
+
 	vec2 dist = vec2(0.5) - abs(tc-vec2(0.5));
 	
 	float det = min(lod/(proj_lod*0.5), 1.0);
@@ -102,7 +145,8 @@ 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);
+
 	vec2 dist = tc-vec2(0.5);
 	
 	float d = dot(dist,dist);
@@ -135,9 +179,9 @@ void main()
 	
 	vec3 pos = getPosition(frag.xy).xyz;
 	vec3 lv = center.xyz-pos.xyz;
-	float dist2 = dot(lv,lv);
-	dist2 /= size;
-	if (dist2 > 1.0)
+	float dist = length(lv);
+	dist /= size;
+	if (dist > 1.0)
 	{
 		discard;
 	}
@@ -154,7 +198,10 @@ void main()
 	}
 	
 	vec3 norm = texture2DRect(normalMap, frag.xy).xyz;
-	norm = (norm.xyz-0.5)*2.0; // unpack norm
+	
+	float envIntensity = norm.z;
+
+	norm = decode_normal(norm.xy);
 	
 	norm = normalize(norm);
 	float l_dist = -dot(lv, proj_n);
@@ -168,7 +215,9 @@ void main()
 	proj_tc.xyz /= proj_tc.w;
 	
 	float fa = falloff+1.0;
-	float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0);
+	float dist_atten = min(1.0-(dist-1.0*(1.0-fa))/fa, 1.0);
+	dist_atten *= dist_atten;
+	dist_atten *= 2.0;
 	if (dist_atten <= 0.0)
 	{
 		discard;
@@ -177,11 +226,15 @@ void main()
 	lv = proj_origin-pos.xyz;
 	lv = normalize(lv);
 	float da = dot(norm, lv);
-		
+
 	vec3 col = vec3(0,0,0);
 		
 	vec3 diff_tex = texture2DRect(diffuseRect, frag.xy).rgb;
-		
+	
+	vec4 spec = texture2DRect(specularRect, frag.xy);
+
+	vec3 dlit = vec3(0, 0, 0);
+
 	float noise = texture2D(noiseMap, frag.xy/128.0).b;
 	if (proj_tc.z > 0.0 &&
 		proj_tc.x < 1.0 &&
@@ -189,21 +242,21 @@ void main()
 		proj_tc.x > 0.0 &&
 		proj_tc.y > 0.0)
 	{
-		float lit = 0.0;
 		float amb_da = proj_ambiance;
-		
+		float lit = 0.0;
+
 		if (da > 0.0)
 		{
+			lit = da * dist_atten * noise;
+
 			float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0);
 			float lod = diff * proj_lod;
 			
 			vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod);
 		
-			vec3 lcol = color.rgb * plcol.rgb * plcol.a;
+			dlit = color.rgb * plcol.rgb * plcol.a;
 			
-			lit = da * dist_atten * noise;
-			
-			col = lcol*lit*diff_tex*shadow;
+			col = dlit*lit*diff_tex*shadow;
 			amb_da += (da*0.5)*(1.0-shadow)*proj_ambiance;
 		}
 		
@@ -219,9 +272,36 @@ void main()
 		col += amb_da*color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a;
 	}
 	
-	
-	vec4 spec = texture2DRect(specularRect, frag.xy);
+
 	if (spec.a > 0.0)
+	{
+		vec3 npos = -normalize(pos);
+		dlit *= 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 += dlit*scol*spec.rgb*shadow;
+			//col += spec.rgb;
+		}
+	}	
+	
+	
+	
+	
+
+	if (envIntensity > 0.0)
 	{
 		vec3 ref = reflect(normalize(pos), norm);
 		
@@ -239,8 +319,9 @@ void main()
 			{
 				stc.xy /= stc.w;
 
-				float fatten = clamp(spec.a*spec.a+spec.a*0.5, 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 &&
@@ -248,8 +329,7 @@ void main()
 					stc.x > 0.0 &&
 					stc.y > 0.0)
 				{
-					vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
-					col += dist_atten*scol.rgb*color.rgb*scol.a*spec.rgb*shadow;
+					col += color.rgb*texture2DLodSpecular(projectionMap, stc.xy, proj_lod-envIntensity*proj_lod).rgb*shadow*spec.rgb;										
 				}
 			}
 		}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
index 9df9d7590577d7ecce14892d8bd95057ac014242..67bac1f7c2e42079d9ddfa9a5bc932bf20d3fa6a 100755
--- a/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/softenLightF.glsl
@@ -38,7 +38,6 @@ uniform sampler2DRect lightMap;
 uniform sampler2DRect depthMap;
 uniform samplerCube environmentMap;
 uniform sampler2D	  lightFunc;
-uniform vec3 gi_quad;
 
 uniform float blur_size;
 uniform float blur_fidelity;
@@ -60,16 +59,13 @@ uniform float density_multiplier;
 uniform float distance_multiplier;
 uniform float max_y;
 uniform vec4 glow;
+uniform float global_gamma;
 uniform float scene_light_strength;
 uniform mat3 env_mat;
 uniform vec4 shadow_clip;
 uniform mat3 ssao_effect_mat;
 
-uniform mat4 inv_proj;
-uniform vec2 screen_res;
-
 uniform vec3 sun_dir;
-
 VARYING vec2 vary_fragcoord;
 
 vec3 vary_PositionEye;
@@ -79,6 +75,43 @@ vec3 vary_AmblitColor;
 vec3 vary_AdditiveColor;
 vec3 vary_AtmosAttenuation;
 
+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);
+	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;
+}
+#endif
+
 vec4 getPosition_d(vec2 pos_screen, float depth)
 {
 	vec2 sc = pos_screen.xy*2.0;
@@ -118,7 +151,6 @@ vec3 getAtmosAttenuation()
 	return vary_AtmosAttenuation;
 }
 
-
 void setPositionEye(vec3 v)
 {
 	vary_PositionEye = v;
@@ -222,6 +254,10 @@ void calcAtmospherics(vec3 inPositionEye, float ambFactor) {
 		  + tmpAmbient)));
 
 	//brightness of surface both sunlight and ambient
+	/*setSunlitColor(pow(vec3(sunlight * .5), vec3(global_gamma)) * global_gamma);
+	setAmblitColor(pow(vec3(tmpAmbient * .25), vec3(global_gamma)) * global_gamma);
+	setAdditiveColor(pow(getAdditiveColor() * vec3(1.0 - temp1), vec3(global_gamma)) * global_gamma);*/
+
 	setSunlitColor(vec3(sunlight * .5));
 	setAmblitColor(vec3(tmpAmbient * .25));
 	setAdditiveColor(getAdditiveColor() * vec3(1.0 - temp1));
@@ -239,6 +275,15 @@ vec3 atmosTransport(vec3 light) {
 	light += getAdditiveColor() * 2.0;
 	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 atmosGetDiffuseSunlightColor()
 {
 	return getSunlitColor();
@@ -273,65 +318,103 @@ vec3 scaleSoftClip(vec3 light)
 	return light;
 }
 
+
+vec3 fullbrightScaleSoftClip(vec3 light)
+{
+	//soft clip effect:
+	return light;
+}
+
 void main() 
 {
 	vec2 tc = vary_fragcoord.xy;
 	float depth = texture2DRect(depthMap, tc.xy).r;
 	vec3 pos = getPosition_d(tc, depth).xyz;
-	vec3 norm = texture2DRect(normalMap, tc).xyz;
-	norm = (norm.xyz-0.5)*2.0; // unpack norm
+	vec4 norm = texture2DRect(normalMap, tc);
+	float envIntensity = norm.z;
+	norm.xyz = decode_normal(norm.xy); // unpack norm
 		
 	float da = max(dot(norm.xyz, sun_dir.xyz), 0.0);
-	
+
+	float light_gamma = 1.0/1.3;
+	da = pow(da, light_gamma);
+
+
 	vec4 diffuse = texture2DRect(diffuseRect, tc);
 
+	//convert to gamma space
+	diffuse.rgb = pow(diffuse.rgb, vec3(1.0/2.2));
+	
 	vec3 col;
 	float bloom = 0.0;
-
-	if (diffuse.a < 0.9)
 	{
 		vec4 spec = texture2DRect(specularRect, vary_fragcoord.xy);
 		
 		vec2 scol_ambocc = texture2DRect(lightMap, vary_fragcoord.xy).rg;
+		scol_ambocc = pow(scol_ambocc, vec2(light_gamma));
+
 		float scol = max(scol_ambocc.r, diffuse.a); 
+
+		
+
 		float ambocc = scol_ambocc.g;
 	
 		calcAtmospherics(pos.xyz, ambocc);
 	
 		col = atmosAmbient(vec3(0));
-		col += atmosAffectDirectionalLight(max(min(da, scol), diffuse.a));
+		float ambient = min(abs(dot(norm.xyz, sun_dir.xyz)), 1.0);
+		ambient *= 0.5;
+		ambient *= ambient;
+		ambient = (1.0-ambient);
+
+		col.rgb *= ambient;
+
+		col += atmosAffectDirectionalLight(max(min(da, scol), 0.0));
 	
 		col *= diffuse.rgb;
 	
+		vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
+
 		if (spec.a > 0.0) // specular reflection
 		{
 			// the old infinite-sky shiny reflection
 			//
-			vec3 refnormpersp = normalize(reflect(pos.xyz, norm.xyz));
+			
 			float sa = dot(refnormpersp, sun_dir.xyz);
-			vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*(6 * texture2D(lightFunc, vec2(sa, spec.a)).r);
-
+			vec3 dumbshiny = vary_SunlitColor*scol_ambocc.r*(texture2D(lightFunc, vec2(sa, spec.a)).r);
+			
 			// add the two types of shiny together
 			vec3 spec_contrib = dumbshiny * spec.rgb;
-			bloom = dot(spec_contrib, spec_contrib) / 4;
+			bloom = dot(spec_contrib, spec_contrib) / 6;
 			col += spec_contrib;
+		}
+	
+		
+		col = mix(col, diffuse.rgb, diffuse.a);
 
-			//add environmentmap
+		if (envIntensity > 0.0)
+		{ //add environmentmap
 			vec3 env_vec = env_mat * refnormpersp;
-			col = mix(col.rgb, textureCube(environmentMap, env_vec).rgb, 
-				max(spec.a-diffuse.a*2.0, 0.0)); 
-		}
 			
-		col = atmosLighting(col);
-		col = scaleSoftClip(col);
+			vec3 refcol = textureCube(environmentMap, env_vec).rgb;
 
-		col = mix(col, diffuse.rgb, diffuse.a);
-	}
-	else
-	{
-		col = diffuse.rgb;
+			col = mix(col.rgb, refcol, 
+				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));
+
+		//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 6d6ad6d5655560e5e07ce8008edf82c6500adb8d..fc0e6b2388991e5297073fafac187290ce002561 100755
--- a/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/spotLightF.glsl
@@ -39,6 +39,7 @@ uniform samplerCube environmentMap;
 uniform sampler2DRect lightMap;
 uniform sampler2D noiseMap;
 uniform sampler2D projectionMap;
+uniform sampler2D lightFunc;
 
 uniform mat4 proj_mat; //screen space to light space
 uniform float proj_near; //near clip for projection
@@ -67,9 +68,49 @@ 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);
+	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;
+}
+#endif
+
+vec4 correctWithGamma(vec4 col)
+{
+	return vec4(pow(col.rgb, vec3(2.2)), col.a);
+}
+
 vec4 texture2DLodSpecular(sampler2D projectionMap, vec2 tc, float lod)
 {
 	vec4 ret = texture2DLod(projectionMap, tc, lod);
+	ret = correctWithGamma(ret);
 	
 	vec2 dist = tc-vec2(0.5);
 	
@@ -85,6 +126,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);
 	
 	vec2 dist = vec2(0.5) - abs(tc-vec2(0.5));
 	
@@ -102,6 +144,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);
 	
 	vec2 dist = tc-vec2(0.5);
 	
@@ -135,9 +178,9 @@ void main()
 	
 	vec3 pos = getPosition(frag.xy).xyz;
 	vec3 lv = trans_center.xyz-pos.xyz;
-	float dist2 = dot(lv,lv);
-	dist2 /= size;
-	if (dist2 > 1.0)
+	float dist = length(lv);
+	dist /= size;
+	if (dist > 1.0)
 	{
 		discard;
 	}
@@ -154,7 +197,8 @@ void main()
 	}
 	
 	vec3 norm = texture2DRect(normalMap, frag.xy).xyz;
-	norm = (norm.xyz-0.5)*2.0; // unpack norm
+	float envIntensity = norm.z;
+	norm = decode_normal(norm.xy);
 	
 	norm = normalize(norm);
 	float l_dist = -dot(lv, proj_n);
@@ -168,7 +212,10 @@ void main()
 	proj_tc.xyz /= proj_tc.w;
 	
 	float fa = falloff+1.0;
-	float dist_atten = min(1.0-(dist2-1.0*(1.0-fa))/fa, 1.0);
+	float dist_atten = min(1.0-(dist-1.0*(1.0-fa))/fa, 1.0);
+	dist_atten *= dist_atten;
+	dist_atten *= 2.0;
+
 	if (dist_atten <= 0.0)
 	{
 		discard;
@@ -182,6 +229,10 @@ void main()
 		
 	vec3 diff_tex = texture2DRect(diffuseRect, frag.xy).rgb;
 		
+	vec4 spec = texture2DRect(specularRect, frag.xy);
+
+	vec3 dlit = vec3(0, 0, 0);
+
 	float noise = texture2D(noiseMap, frag.xy/128.0).b;
 	if (proj_tc.z > 0.0 &&
 		proj_tc.x < 1.0 &&
@@ -189,21 +240,21 @@ void main()
 		proj_tc.x > 0.0 &&
 		proj_tc.y > 0.0)
 	{
-		float lit = 0.0;
 		float amb_da = proj_ambiance;
+		float lit = 0.0;
 		
 		if (da > 0.0)
 		{
+			lit = da * dist_atten * noise;
+
 			float diff = clamp((l_dist-proj_focus)/proj_range, 0.0, 1.0);
 			float lod = diff * proj_lod;
 			
 			vec4 plcol = texture2DLodDiffuse(projectionMap, proj_tc.xy, lod);
 		
-			vec3 lcol = color.rgb * plcol.rgb * plcol.a;
-			
-			lit = da * dist_atten * noise;
+			dlit = color.rgb * plcol.rgb * plcol.a;
 			
-			col = lcol*lit*diff_tex*shadow;
+			col = dlit*lit*diff_tex*shadow;
 			amb_da += (da*0.5)*(1.0-shadow)*proj_ambiance;
 		}
 		
@@ -219,9 +270,36 @@ void main()
 		col += amb_da*color.rgb*diff_tex.rgb*amb_plcol.rgb*amb_plcol.a;
 	}
 	
-	
-	vec4 spec = texture2DRect(specularRect, frag.xy);
+
 	if (spec.a > 0.0)
+	{
+		dlit *= min(da*6.0, 1.0) * dist_atten;
+		vec3 npos = -normalize(pos);
+
+		//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 += dlit*scol*spec.rgb*shadow;
+			//col += spec.rgb;
+		}
+	}	
+	
+	
+	
+	
+
+	if (envIntensity > 0.0)
 	{
 		vec3 ref = reflect(normalize(pos), norm);
 		
@@ -239,8 +317,9 @@ void main()
 			{
 				stc.xy /= stc.w;
 
-				float fatten = clamp(spec.a*spec.a+spec.a*0.5, 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 &&
@@ -248,8 +327,7 @@ void main()
 					stc.x > 0.0 &&
 					stc.y > 0.0)
 				{
-					vec4 scol = texture2DLodSpecular(projectionMap, stc.xy, proj_lod-spec.a*proj_lod);
-					col += dist_atten*scol.rgb*color.rgb*scol.a*spec.rgb*shadow;
+					col += color.rgb*texture2DLodSpecular(projectionMap, stc.xy, proj_lod-envIntensity*proj_lod).rgb*shadow*spec.rgb;										
 				}
 			}
 		}
diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
index 890486c4b1dcab790fd6c9e33eb82255dcefab0b..7b09dd29ddec1029163a47badfd5c8afb5335380 100755
--- a/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightF.glsl
@@ -65,6 +65,40 @@ 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);
+	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;
+}
+#endif
+
 vec4 getPosition(vec2 pos_screen)
 {
 	float depth = texture2DRect(depthMap, pos_screen.xy).r;
@@ -125,11 +159,9 @@ void main()
 	
 	vec4 pos = getPosition(pos_screen);
 	
-	vec4 nmap4 = texture2DRect(normalMap, pos_screen);
-	nmap4 = vec4((nmap4.xyz-0.5)*2.0,nmap4.w); // unpack norm
-	float displace = nmap4.w;
-	vec3 norm = nmap4.xyz;
-	
+	vec3 norm = texture2DRect(normalMap, pos_screen).xyz;
+	norm = decode_normal(norm.xy); // unpack norm
+		
 	/*if (pos.z == 0.0) // do nothing for sky *FIX: REMOVE THIS IF/WHEN THE POSITION MAP IS BEING USED AS A STENCIL
 	{
 		frag_color = vec4(0.0); // doesn't matter
@@ -138,8 +170,8 @@ void main()
 	
 	float shadow = 0.0;
 	float dp_directional_light = max(0.0, dot(norm, sun_dir.xyz));
-
-	vec3 shadow_pos = pos.xyz + displace*norm;
+	
+	vec3 shadow_pos = pos.xyz;
 	vec3 offset = sun_dir.xyz * (1.0-dp_directional_light);
 	
 	vec4 spos = vec4(shadow_pos+offset*shadow_offset, 1.0);
diff --git a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl
index 2dcd3d656fd8ca480d3f50c8e841f8f4e3ef9d0b..01e34ed792547cc994992145db801e27abf3db2a 100755
--- a/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl
+++ b/indra/newview/app_settings/shaders/class2/deferred/sunLightSSAOF.glsl
@@ -66,6 +66,40 @@ 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);
+	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;
+}
+#endif
+
 vec4 getPosition(vec2 pos_screen)
 {
 	float depth = texture2DRect(depthMap, pos_screen.xy).r;
@@ -186,11 +220,9 @@ void main()
 	
 	vec4 pos = getPosition(pos_screen);
 	
-	vec4 nmap4 = texture2DRect(normalMap, pos_screen);
-	nmap4 = vec4((nmap4.xyz-0.5)*2.0,nmap4.w); // unpack norm
-	float displace = nmap4.w;
-	vec3 norm = nmap4.xyz;
-	
+	vec3 norm = texture2DRect(normalMap, pos_screen).xyz;
+	norm = decode_normal(norm.xy); // unpack norm
+		
 	/*if (pos.z == 0.0) // do nothing for sky *FIX: REMOVE THIS IF/WHEN THE POSITION MAP IS BEING USED AS A STENCIL
 	{
 		frag_color = vec4(0.0); // doesn't matter
@@ -199,8 +231,8 @@ void main()
 	
 	float shadow = 0.0;
 	float dp_directional_light = max(0.0, dot(norm, sun_dir.xyz));
-
-	vec3 shadow_pos = pos.xyz + displace*norm;
+	
+	vec3 shadow_pos = pos.xyz;
 	vec3 offset = sun_dir.xyz * (1.0-dp_directional_light);
 	
 	vec4 spos = vec4(shadow_pos+offset*shadow_offset, 1.0);
diff --git a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsV.glsl b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsV.glsl
index da3d922017db3ed7844e544e647ba19260ddb758..d174805cc08c739c70b2255b4aafbdc096547dc9 100755
--- a/indra/newview/app_settings/shaders/class2/windlight/atmosphericsV.glsl
+++ b/indra/newview/app_settings/shaders/class2/windlight/atmosphericsV.glsl
@@ -129,7 +129,7 @@ void calcAtmospherics(vec3 inPositionEye) {
 		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));
diff --git a/indra/newview/character/avatar_lad.xml b/indra/newview/character/avatar_lad.xml
index 284e9c44b286ee6b4352b2f47759395eac54aed9..e5b385f4aa3f66edac719dd119342ca65bf9208c 100755
--- a/indra/newview/character/avatar_lad.xml
+++ b/indra/newview/character/avatar_lad.xml
@@ -1084,8 +1084,7 @@
          scale="0 0 .5" />
       </param_skeleton>
     </param>
-
-    <param
+                          <param
      id="11001"
      group="0"
      name="Hover"
@@ -12308,7 +12307,7 @@ render_pass="bump">
 	 <param_driver />
     </param>
 
-    <param
+  <param
      id="11000"
      group="0"
      name="AppearanceMessage_Version"
diff --git a/indra/newview/gpu_table.txt b/indra/newview/gpu_table.txt
index 4c39014c8b5238a1cdfc75d41fd96fad94ccab47..c64e11929df8b09d55a9d2787487405d50eb2c3e 100755
--- a/indra/newview/gpu_table.txt
+++ b/indra/newview/gpu_table.txt
@@ -32,20 +32,20 @@
 //		1 - We claim to support this card.
 //
 
-3Dfx									.*3Dfx.*								0	0	0	0
-3Dlabs									.*3Dlabs.*								0	0	0	0
-ATI 3D-Analyze							.*ATI.*3D-Analyze.*						0	0	0	0
-ATI All-in-Wonder 7500					.*ATI.*All-in-Wonder 75.*				0	1	0	0
-ATI All-in-Wonder 8500					.*ATI.*All-in-Wonder 85.*				0	1	0	0
-ATI All-in-Wonder 9200					.*ATI.*All-in-Wonder 92.*				0	1	0	0
+3Dfx									.*3Dfx.*											0	0	0	0
+3Dlabs									.*3Dlabs.*											0	0	0	0
+ATI 3D-Analyze							.*ATI.*3D-Analyze.*									0	0	0	0
+ATI All-in-Wonder 7500					.*ATI.*All-in-Wonder 75.*							0	1	0	0
+ATI All-in-Wonder 8500					.*ATI.*All-in-Wonder 85.*							0	1	0	0
+ATI All-in-Wonder 9200					.*ATI.*All-in-Wonder 92.*							0	1	0	0
 ATI All-in-Wonder 9xxx					.*ATI.*All-in-Wonder 9.*				1	1	0	0
-ATI All-in-Wonder HD					.*ATI.*All-in-Wonder HD.*				1	1	1	3.3
-ATI All-in-Wonder X600					.*ATI.*All-in-Wonder X6.*				1	1	0	0
-ATI All-in-Wonder X800					.*ATI.*All-in-Wonder X8.*				1	1	1	2.1
-ATI All-in-Wonder X1800					.*ATI.*All-in-Wonder X18.*				3	1	0	0
-ATI All-in-Wonder X1900					.*ATI.*All-in-Wonder X19.*				3	1	0	0
-ATI All-in-Wonder PCI-E					.*ATI.*All-in-Wonder.*PCI-E.*			1	1	0	0
-ATI All-in-Wonder Radeon				.*ATI.*All-in-Wonder Radeon.*			0	1	0	0
+ATI All-in-Wonder HD					.*ATI.*All-in-Wonder HD.*							1	1	1	3.3
+ATI All-in-Wonder X600					.*ATI.*All-in-Wonder X6.*							1	1	0	0
+ATI All-in-Wonder X800					.*ATI.*All-in-Wonder X8.*							1	1	1	2.1
+ATI All-in-Wonder X1800					.*ATI.*All-in-Wonder X18.*							3	1	0	0
+ATI All-in-Wonder X1900					.*ATI.*All-in-Wonder X19.*							3	1	0	0
+ATI All-in-Wonder PCI-E					.*ATI.*All-in-Wonder.*PCI-E.*						1	1	0	0
+ATI All-in-Wonder Radeon				.*ATI.*All-in-Wonder Radeon.*						0	1	0	0
 ATI ASUS ARES							.*ATI.*ASUS.*ARES.*						3	1	0	0
 ATI ASUS A9xxx							.*ATI.*ASUS.*A9.*						1	1	0	0
 ATI ASUS AH24xx							.*ATI.*ASUS.*AH24.*						1	1	1	3.3
@@ -79,30 +79,30 @@ ATI ASUS Radeon X1xxx					.*ATI.*ASUS.*X1.*						2	1	1	2.1
 ATI Radeon X7xx							.*ATI.*ASUS.*X7.*						1	1	0	0
 ATI Radeon X19xx						.*ATI.*(Radeon|Diamond) X19.* ?.*		2	1	1	2.1
 ATI Radeon X18xx						.*ATI.*(Radeon|Diamond) X18.* ?.*		3	1	1	2.1
-ATI Radeon X17xx						.*ATI.*(Radeon|Diamond) X17.* ?.*		1	1	1	2.1
+ATI Radeon X17xx						.*ATI.*(Radeon|Diamond) X17.* ?.*					1	1	1	2.1
 ATI Radeon X16xx						.*ATI.*(Radeon|Diamond) X16.* ?.*		1	1	1	2.1
 ATI Radeon X15xx						.*ATI.*(Radeon|Diamond) X15.* ?.*		1	1	1	2.1
 ATI Radeon X13xx						.*ATI.*(Radeon|Diamond) X13.* ?.*		1	1	1	2.1
 ATI Radeon X1xxx						.*ATI.*(Radeon|Diamond) X1.. ?.*		0	1	1	2.1
 ATI Radeon X2xxx						.*ATI.*(Radeon|Diamond) X2.. ?.*		1	1	1	2.1
-ATI Display Adapter						.*ATI.*display adapter.*				1	1	1	4.1
-ATI FireGL 5200							.*ATI.*FireGL V52.*						1	1	1	2.1
-ATI FireGL 5xxx							.*ATI.*FireGL V5.*						2	1	1	3.3
-ATI FireGL								.*ATI.*Fire.*GL.*						4	1	1	4.2
+ATI Display Adapter						.*ATI.*display adapter.*							1	1	1	4.1
+ATI FireGL 5200							.*ATI.*FireGL V52.*									1	1	1	2.1
+ATI FireGL 5xxx							.*ATI.*FireGL V5.*									2	1	1	3.3
+ATI FireGL								.*ATI.*Fire.*GL.*									4	1	1	4.2
 ATI FirePro M3900						.*ATI.*FirePro.*M39.*					2	1	0	0
-ATI FirePro M5800						.*ATI.*FirePro.*M58.*					3	1	0	0
-ATI FirePro M7740						.*ATI.*FirePro.*M77.*					3	1	0	0
-ATI FirePro M7820						.*ATI.*FirePro.*M78.*					5	1	1	4.2
+ATI FirePro M5800						.*ATI.*FirePro.*M58.*								3	1	0	0
+ATI FirePro M7740						.*ATI.*FirePro.*M77.*								3	1	0	0
+ATI FirePro M7820						.*ATI.*FirePro.*M78.*								5	1	1	4.2
 ATI FireMV								.*ATI.*FireMV.*							0	1	1	1.3
-ATI Generic								.*ATI.*Generic.*						0	0	0	0
-ATI Hercules 9800						.*ATI.*Hercules.*9800.*					1	1	0	0
+ATI Generic								.*ATI.*Generic.*									0	0	0	0
+ATI Hercules 9800						.*ATI.*Hercules.* 9800.*							1	1	0	0
 ATI IGP 340M							.*ATI.*IGP.*340M.*						0	0	0	0
-ATI M52									.*ATI.*M52.*							1	1	0	0
-ATI M54									.*ATI.*M54.*							1	1	0	0
-ATI M56									.*ATI.*M56.*							1	1	0	0
-ATI M71									.*ATI.*M71.*							1	1	0	0
-ATI M72									.*ATI.*M72.*							1	1	0	0
-ATI M76									.*ATI.*M76.*							3	1	0	0
+ATI M52									.*ATI.*M52.*										1	1	0	0
+ATI M54									.*ATI.*M54.*										1	1	0	0
+ATI M56									.*ATI.*M56.*										1	1	0	0
+ATI M71									.*ATI.*M71.*										1	1	0	0
+ATI M72									.*ATI.*M72.*										1	1	0	0
+ATI M76									.*ATI.*M76.*										3	1	0	0
 ATI Radeon HD 64xx						.*ATI.*AMD Radeon.* HD [67]4..[MG]		2	1	1	4.2
 ATI Radeon HD 65xx						.*ATI.*AMD Radeon.* HD [67]5..[MG]		2	1	1	4.2
 ATI Radeon HD 66xx						.*ATI.*AMD Radeon.* HD [67]6..[MG]		3	1	1	4.2
@@ -124,12 +124,12 @@ ATI ASUS HD7600							.*ATI.*ASUS.* HD76.*					3	1	0	0
 ATI ASUS HD7700							.*ATI.*ASUS.* HD77.*					4	1	1	4.2
 ATI ASUS HD7800							.*ATI.*ASUS.* HD78.*					5	1	1	4.2
 ATI ASUS HD7900							.*ATI.*ASUS.* HD79.*					5	1	1	4.2
-ATI Mobility Radeon 4100				.*ATI.*Mobility.*41..					1	1	1	3.3
-ATI Mobility Radeon 7xxx				.*ATI.*Mobility.*Radeon 7.*				0	1	1	1.3
-ATI Mobility Radeon 8xxx				.*ATI.*Mobility.*Radeon 8.*				0	1	0	0
-ATI Mobility Radeon 9800				.*ATI.*Mobility.*98.*					1	1	0	0
-ATI Mobility Radeon 9700				.*ATI.*Mobility.*97.*					0	1	1	2.1
-ATI Mobility Radeon 9600				.*ATI.*Mobility.*96.*					1	1	1	2.1
+ATI Mobility Radeon 4100				.*ATI.*Mobility.* 41..								1	1	1	3.3
+ATI Mobility Radeon 7xxx				.*ATI.*Mobility.*Radeon 7.*							0	1	1	1.3
+ATI Mobility Radeon 8xxx				.*ATI.*Mobility.*Radeon 8.*							0	1	0	0
+ATI Mobility Radeon 9800				.*ATI.*Mobility.* 98.*								1	1	0	0
+ATI Mobility Radeon 9700				.*ATI.*Mobility.* 97.*								0	1	1	2.1
+ATI Mobility Radeon 9600				.*ATI.*Mobility.* 96.*								1	1	1	2.1
 ATI Mobility Radeon HD 530v				.*ATI.*Mobility.*HD *530v.*				1	1	1	3.3
 ATI Mobility Radeon HD 540v				.*ATI.*Mobility.*HD *540v.*				1	1	1	3.3
 ATI Mobility Radeon HD 545v				.*ATI.*Mobility.*HD *545v.*				2	1	1	4
@@ -176,7 +176,7 @@ ATI Radeon HD 3400						.*ATI.*Radeon HD *34..					1	1	1	4
 ATI Radeon HD 3500						.*ATI.*Radeon HD *35..					2	1	0	0
 ATI Radeon HD 3600						.*ATI.*Radeon HD *36..					3	1	1	3.3
 ATI Radeon HD 3700						.*ATI.*Radeon HD *37..					3	1	0	0
-ATI HD3700								.*ATI.* HD37..							3	1	0	3.3
+ATI HD3700								.*ATI.* HD37..										3	1	0	3.3
 ATI Radeon HD 3800						.*ATI.*Radeon HD *38..					3	1	1	4
 ATI Radeon HD 4100						.*ATI.*Radeon HD *41..					1	1	0	0
 ATI Radeon HD 4200						.*ATI.*Radeon HD *42..					1	1	1	4
@@ -202,128 +202,128 @@ ATI Radeon HD 6600						.*ATI.*Radeon HD *66..					3	1	1	4.2
 ATI Radeon HD 6700						.*ATI.*Radeon HD *67..					3	1	1	4.2
 ATI Radeon HD 6800						.*ATI.*Radeon HD *68..					4	1	1	4.2
 ATI Radeon HD 6900						.*ATI.*Radeon HD *69..					5	1	1	4.2
-ATI Radeon OpenGL						.*ATI.*Radeon OpenGL.*					0	0	0	0
-ATI Radeon 2100							.*ATI.*Radeon 21..						0	1	1	2.1
-ATI Radeon 3000							.*ATI.*Radeon 30..						1	1	1	4
-ATI Radeon 3100							.*ATI.*Radeon 31..						0	1	1	3.3
-ATI Radeon 5xxx							.*ATI.*Radeon 5...						3	1	0	0
-ATI Radeon 7xxx							.*ATI.*Radeon 7...						0	1	1	2
-ATI Radeon 8xxx							.*ATI.*Radeon 8...						0	1	0	0
-ATI Radeon 9000							.*ATI.*Radeon 90..						0	1	1	1.3
-ATI Radeon 9100							.*ATI.*Radeon 91..						0	1	0	0
-ATI Radeon 9200							.*ATI.*Radeon 92..						0	1	1	1.3
-ATI Radeon 9500							.*ATI.*Radeon 95..						0	1	1	2.1
-ATI Radeon 9600							.*ATI.*Radeon 96..						0	1	1	2.1
-ATI Radeon 9700							.*ATI.*Radeon 97..						1	1	0	0
-ATI Radeon 9800							.*ATI.*Radeon 98..						1	1	1	2.1
-ATI Radeon RV250						.*ATI.*RV250.*							0	1	0	0
-ATI Radeon RV600						.*ATI.*RV6.*							1	1	0	0
-ATI Radeon RX700						.*ATI.*RX70.*							1	1	0	0
+ATI Radeon OpenGL						.*ATI.*Radeon OpenGL.*								0	0	0	0
+ATI Radeon 2100							.*ATI.*Radeon 21..									0	1	1	2.1
+ATI Radeon 3000							.*ATI.*Radeon 30..									1	1	1	4
+ATI Radeon 3100							.*ATI.*Radeon 31..									0	1	1	3.3
+ATI Radeon 5xxx							.*ATI.*Radeon 5...									3	1	0	0
+ATI Radeon 7xxx							.*ATI.*Radeon 7...									0	1	1	2
+ATI Radeon 8xxx							.*ATI.*Radeon 8...									0	1	0	0
+ATI Radeon 9000							.*ATI.*Radeon 90..									0	1	1	1.3
+ATI Radeon 9100							.*ATI.*Radeon 91..									0	1	0	0
+ATI Radeon 9200							.*ATI.*Radeon 92..									0	1	1	1.3
+ATI Radeon 9500							.*ATI.*Radeon 95..									0	1	1	2.1
+ATI Radeon 9600							.*ATI.*Radeon 96..									0	1	1	2.1
+ATI Radeon 9700							.*ATI.*Radeon 97..									1	1	0	0
+ATI Radeon 9800							.*ATI.*Radeon 98..									1	1	1	2.1
+ATI Radeon RV250						.*ATI.*RV250.*										0	1	0	0
+ATI Radeon RV600						.*ATI.*RV6.*										1	1	0	0
+ATI Radeon RX700						.*ATI.*RX70.*										1	1	0	0
 ATI Radeon RX800						.*ATI.*Radeon *RX80.*					2	1	0	0
-ATI RS880M								.*ATI.*RS880M							1	1	0	0
-ATI Radeon RX9550						.*ATI.*RX9550.*							1	1	0	0
-ATI Radeon VE							.*ATI.*Radeon.*VE.*						0	0	0	0
+ATI RS880M								.*ATI.*RS880M										1	1	0	0
+ATI Radeon RX9550						.*ATI.*RX9550.*										1	1	0	0
+ATI Radeon VE							.*ATI.*Radeon.*VE.*									0	0	0	0
 ATI Radeon X300							.*ATI.*Radeon *X3.*						1	1	1	2.1
-ATI Radeon X400							.*ATI.*Radeon ?X4.*						0	1	0	0
-ATI Radeon X500							.*ATI.*Radeon ?X5.*						1	1	1	2.1
+ATI Radeon X400							.*ATI.*Radeon ?X4.*									0	1	0	0
+ATI Radeon X500							.*ATI.*Radeon ?X5.*									1	1	1	2.1
 ATI Radeon X600							.*ATI.*Radeon ?X6.*						1	1	1	2.1
-ATI Radeon X700							.*ATI.*Radeon ?X7.*						2	1	1	2.1
-ATI Radeon X800							.*ATI.*Radeon ?X8.*						1	1	1	2.1
-ATI Radeon X900							.*ATI.*Radeon ?X9.*						2	1	0	0
-ATI Radeon Xpress						.*ATI.*Radeon Xpress.*					0	1	1	2.1
-ATI Rage 128							.*ATI.*Rage 128.*						0	1	0	0
-ATI R300 (9700)							.*R300.*								0	1	1	2.1
-ATI R350 (9800)							.*R350.*								1	1	0	0
-ATI R580 (X1900)						.*R580.*								3	1	0	0
-ATI RC410 (Xpress 200)					.*RC410.*								0	0	0	0
-ATI RS48x (Xpress 200x)					.*RS48.*								0	0	0	0
-ATI RS600 (Xpress 3200)					.*RS600.*								0	0	0	0
-ATI RV350 (9600)						.*RV350.*								0	1	0	0
-ATI RV370 (X300)						.*RV370.*								0	1	0	0
-ATI RV410 (X700)						.*RV410.*								1	1	0	0
-ATI RV515								.*RV515.*								1	1	0	0
-ATI RV570 (X1900 GT/PRO)				.*RV570.*								3	1	0	0
-ATI RV380								.*RV380.*								0	1	0	0
-ATI RV530								.*RV530.*								1	1	0	0
-ATI RX480 (Xpress 200P)					.*RX480.*								0	1	0	0
-ATI RX700								.*RX700.*								1	1	0	0
-AMD ANTILLES (HD 6990)					.*(AMD|ATI).*Antilles.*					3	1	0	0
-AMD BARTS (HD 6800)						.*(AMD|ATI).*Barts.*					3	1	1	2.1
-AMD CAICOS (HD 6400)					.*(AMD|ATI).*Caicos.*					3	1	0	0
-AMD CAYMAN (HD 6900)					.*(AMD|ATI).*(Cayman|CAYMAM).*			3	1	0	0
+ATI Radeon X700							.*ATI.*Radeon ?X7.*									2	1	1	2.1
+ATI Radeon X800							.*ATI.*Radeon ?X8.*									1	1	1	2.1
+ATI Radeon X900							.*ATI.*Radeon ?X9.*									2	1	0	0
+ATI Radeon Xpress						.*ATI.*Radeon Xpress.*								0	1	1	2.1
+ATI Rage 128							.*ATI.*Rage 128.*									0	1	0	0
+ATI R300 (9700)							.*R300.*											0	1	1	2.1
+ATI R350 (9800)							.*R350.*											1	1	0	0
+ATI R580 (X1900)						.*R580.*											3	1	0	0
+ATI RC410 (Xpress 200)					.*RC410.*											0	0	0	0
+ATI RS48x (Xpress 200x)					.*RS48.*											0	0	0	0
+ATI RS600 (Xpress 3200)					.*RS600.*											0	0	0	0
+ATI RV350 (9600)						.*RV350.*											0	1	0	0
+ATI RV370 (X300)						.*RV370.*											0	1	0	0
+ATI RV410 (X700)						.*RV410.*											1	1	0	0
+ATI RV515								.*RV515.*											1	1	0	0
+ATI RV570 (X1900 GT/PRO)				.*RV570.*											3	1	0	0
+ATI RV380								.*RV380.*											0	1	0	0
+ATI RV530								.*RV530.*											1	1	0	0
+ATI RX480 (Xpress 200P)					.*RX480.*											0	1	0	0
+ATI RX700								.*RX700.*											1	1	0	0
+AMD ANTILLES (HD 6990)					.*(AMD|ATI).*Antilles.*								3	1	0	0
+AMD BARTS (HD 6800)						.*(AMD|ATI).*Barts.*								3	1	1	2.1
+AMD CAICOS (HD 6400)					.*(AMD|ATI).*Caicos.*								3	1	0	0
+AMD CAYMAN (HD 6900)					.*(AMD|ATI).*(Cayman|CAYMAM).*						3	1	0	0
 AMD CEDAR (HD 5450)						.*(AMD|ATI).*Cedar.*					2	1	0	0
-AMD CYPRESS (HD 5800)					.*(AMD|ATI).*Cypress.*					3	1	0	0
-AMD HEMLOCK (HD 5970)					.*(AMD|ATI).*Hemlock.*					3	1	0	0
-AMD JUNIPER (HD 5700)					.*(AMD|ATI).*Juniper.*					3	1	0	0
-AMD PARK								.*(AMD|ATI).*Park.*						3	1	0	0
+AMD CYPRESS (HD 5800)					.*(AMD|ATI).*Cypress.*								3	1	0	0
+AMD HEMLOCK (HD 5970)					.*(AMD|ATI).*Hemlock.*								3	1	0	0
+AMD JUNIPER (HD 5700)					.*(AMD|ATI).*Juniper.*								3	1	0	0
+AMD PARK								.*(AMD|ATI).*Park.*									3	1	0	0
 AMD REDWOOD (HD 5500/5600)				.*(AMD|ATI).*Redwood.*					3	1	0	0
 AMD TURKS (HD 6500/6600)				.*(AMD|ATI).*Turks.*					3	1	0	0
-AMD RS780 (HD 3200)						.*RS780.*								0	1	1	2.1
-AMD RS880 (HD 4200)						.*RS880.*								0	1	1	3.2
-AMD RV610 (HD 2400)						.*RV610.*								1	1	0	0
-AMD RV620 (HD 3400)						.*RV620.*								1	1	0	0
-AMD RV630 (HD 2600)						.*RV630.*								2	1	0	0
+AMD RS780 (HD 3200)						.*RS780.*											0	1	1	2.1
+AMD RS880 (HD 4200)						.*RS880.*											0	1	1	3.2
+AMD RV610 (HD 2400)						.*RV610.*											1	1	0	0
+AMD RV620 (HD 3400)						.*RV620.*											1	1	0	0
+AMD RV630 (HD 2600)						.*RV630.*											2	1	0	0
 AMD RV635 (HD 3600)						.*RV635.*								3	1	0	0
-AMD RV670 (HD 3800)						.*RV670.*								3	1	0	0
-AMD R680 (HD 3870 X2)					.*R680.*								3	1	0	0
-AMD R700 (HD 4800 X2)					.*R700.*								3	1	0	0
-AMD RV710 (HD 4300)						.*RV710.*								0	1	1	1.4
+AMD RV670 (HD 3800)						.*RV670.*											3	1	0	0
+AMD R680 (HD 3870 X2)					.*R680.*											3	1	0	0
+AMD R700 (HD 4800 X2)					.*R700.*											3	1	0	0
+AMD RV710 (HD 4300)						.*RV710.*											0	1	1	1.4
 AMD RV730 (HD 4600)						.*RV730.*								3	1	0	0
-AMD RV740 (HD 4700)						.*RV740.*								3	1	0	0
-AMD RV770 (HD 4800)						.*RV770.*								3	1	0	0
-AMD RV790 (HD 4800)						.*RV790.*								3	1	0	0
-ATI 760G/Radeon 3000					.*ATI.*AMD 760G.*						1	1	1	3.3
-ATI 780L/Radeon 3000					.*ATI.*AMD 780L.*						1	1	0	0
-ATI Radeon DDR							.*ATI.*Radeon ?DDR.*					0	1	0	0
+AMD RV740 (HD 4700)						.*RV740.*											3	1	0	0
+AMD RV770 (HD 4800)						.*RV770.*											3	1	0	0
+AMD RV790 (HD 4800)						.*RV790.*											3	1	0	0
+ATI 760G/Radeon 3000					.*ATI.*AMD 760G.*									1	1	1	3.3
+ATI 780L/Radeon 3000					.*ATI.*AMD 780L.*									1	1	0	0
+ATI Radeon DDR							.*ATI.*Radeon ?DDR.*								0	1	0	0
 ATI FirePro 2000						.*ATI.*FirePro 2.*						2	1	1	4.1
-ATI FirePro 3000						.*ATI.*FirePro V3.*						2	1	0	0
+ATI FirePro 3000						.*ATI.*FirePro V3.*									2	1	0	0
 ATI FirePro 4000						.*ATI.*FirePro V4.*						2	1	0	0
-ATI FirePro 5000						.*ATI.*FirePro V5.*						3	1	0	0
-ATI FirePro 7000						.*ATI.*FirePro V7.*						3	1	0	0
-ATI FirePro M							.*ATI.*FirePro M.*						3	1	1	4.2
-ATI R300 (9700)							.*R300.*								0	1	1	2.1
+ATI FirePro 5000						.*ATI.*FirePro V5.*									3	1	0	0
+ATI FirePro 7000						.*ATI.*FirePro V7.*									3	1	0	0
+ATI FirePro M							.*ATI.*FirePro M.*									3	1	1	4.2
+ATI R300 (9700)							.*R300.*											0	1	1	2.1
 ATI Radeon								.*ATI.*(Diamond|Radeon).*				0	1	0	4.2
-Intel X3100								.*Intel.*X3100.*						1	1	1	2.1
-Intel GMA 3600							.*Intel.* 3600.*						0	1	1	3
-Intel 830M								.*Intel.*830M							0	0	0	0
-Intel 845G								.*Intel.*845G							0	0	1	1.4
-Intel 855GM								.*Intel.*855GM							0	0	1	1.4
-Intel 865G								.*Intel.*865G							0	0	1	1.4
-Intel 900								.*Intel.*900.*900						0	0	0	0
-Intel 915GM								.*Intel.*915GM							0	0	1	1.4
-Intel 915G								.*Intel.*915G							0	0	1	1.4
-Intel 945GM								.*Intel.*945GM.*						0	1	1	1.4
-Intel 945G								.*Intel.*945G.*							0	1	1	1.4
-Intel 950								.*Intel.*950.*							0	1	1	1.4
-Intel 965								.*Intel.*965.*							0	1	1	2.1
-Intel G33								.*Intel.*G33.*							1	0	1	1.4
-Intel G41								.*Intel.*G41.*							1	1	1	2.1
-Intel G45								.*Intel.*G45.*							1	1	1	2.1
-Intel Bear Lake							.*Intel.*Bear Lake.*					1	0	1	1.4
-Intel Broadwater						.*Intel.*Broadwater.*					0	0	1	1.4
-Intel Brookdale							.*Intel.*Brookdale.*					0	0	1	1.3
-Intel Cantiga							.*Intel.*Cantiga.*						0	0	1	2
-Intel Eaglelake							.*Intel.*Eaglelake.*					1	1	1	2
-Intel Graphics Media HD					.*Intel.*Graphics Media.*HD.*			1	1	1	2.1
-Intel HD Graphics 2000					.*Intel.*HD Graphics 2.*				2	1	0	4
-Intel HD Graphics 3000					.*Intel.*HD Graphics 3.*				3	1	1	3.1
-Intel HD Graphics 4000					.*Intel.*HD Graphics 4.*				3	1	1	4
+Intel X3100								.*Intel.*X3100.*									1	1	1	2.1
+Intel GMA 3600							.*Intel.* 3600.*									0	1	1	3
+Intel 830M								.*Intel.*830M										0	0	0	0
+Intel 845G								.*Intel.*845G										0	0	1	1.4
+Intel 855GM								.*Intel.*855GM										0	0	1	1.4
+Intel 865G								.*Intel.*865G										0	0	1	1.4
+Intel 900								.*Intel.*900.*900									0	0	0	0
+Intel 915GM								.*Intel.*915GM										0	0	1	1.4
+Intel 915G								.*Intel.*915G										0	0	1	1.4
+Intel 945GM								.*Intel.*945GM.*									0	1	1	1.4
+Intel 945G								.*Intel.*945G.*										0	1	1	1.4
+Intel 950								.*Intel.*950.*										0	1	1	1.4
+Intel 965								.*Intel.*965.*										0	1	1	2.1
+Intel G33								.*Intel.*G33.*										1	0	1	1.4
+Intel G41								.*Intel.*G41.*										1	1	1	2.1
+Intel G45								.*Intel.*G45.*										1	1	1	2.1
+Intel Bear Lake							.*Intel.*Bear Lake.*								1	0	1	1.4
+Intel Broadwater						.*Intel.*Broadwater.*								0	0	1	1.4
+Intel Brookdale							.*Intel.*Brookdale.*								0	0	1	1.3
+Intel Cantiga							.*Intel.*Cantiga.*									0	0	1	2
+Intel Eaglelake							.*Intel.*Eaglelake.*								1	1	1	2
+Intel Graphics Media HD					.*Intel.*Graphics Media.*HD.*						1	1	1	2.1
+Intel HD Graphics 2000					.*Intel.*HD Graphics 2.*							2	1	0	4
+Intel HD Graphics 3000					.*Intel.*HD Graphics 3.*							3	1	1	3.1
+Intel HD Graphics 4000					.*Intel.*HD Graphics 4.*							3	1	1	4
 Intel HD2000							.*Intel.*HD2000.*						2	1	0	0
 Intel HD3000							.*Intel.*HD3000.*						3	1	0	0
-Intel HD Graphics						.*Intel.*HD Graphics.*					2	1	1	4
-Intel Mobile 4 Series					.*Intel.*Mobile.* 4 Series.*			0	1	1	2.1
-Intel 4 Series Internal					.*Intel.* 4 Series Internal.*			1	1	1	2.1
-Intel Media Graphics HD					.*Intel.*Media Graphics HD.*			0	1	0	0
-Intel Montara							.*Intel.*Montara.*						0	0	1	1.3
-Intel Pineview							.*Intel.*Pineview.*						0	1	1	1.4
-Intel Springdale						.*Intel.*Springdale.*					0	0	1	1.3
-Intel Grantsdale						.*Intel.*Grantsdale.*					1	1	0	0
-Intel Q45/Q43							.*Intel.*Q4.*							1	1	1	2.1
-Intel B45/B43							.*Intel.*B4.*							1	1	1	2.1
-Intel 3D-Analyze						.*Intel.*3D-Analyze.*					2	1	0	0
-Matrox									.*Matrox.*								0	0	0	0
+Intel HD Graphics						.*Intel.*HD Graphics.*								2	1	1	4
+Intel Mobile 4 Series					.*Intel.*Mobile.* 4 Series.*						0	1	1	2.1
+Intel 4 Series Internal					.*Intel.* 4 Series Internal.*						1	1	1	2.1
+Intel Media Graphics HD					.*Intel.*Media Graphics HD.*						0	1	0	0
+Intel Montara							.*Intel.*Montara.*									0	0	1	1.3
+Intel Pineview							.*Intel.*Pineview.*									0	1	1	1.4
+Intel Springdale						.*Intel.*Springdale.*								0	0	1	1.3
+Intel Grantsdale						.*Intel.*Grantsdale.*								1	1	0	0
+Intel Q45/Q43							.*Intel.*Q4.*										1	1	1	2.1
+Intel B45/B43							.*Intel.*B4.*										1	1	1	2.1
+Intel 3D-Analyze						.*Intel.*3D-Analyze.*								2	1	0	0
+Matrox									.*Matrox.*											0	0	0	0
 Mesa									.*Mesa.*								1	0	1	2.1
-Gallium									.*Gallium.*								1	1	1	2.1
+Gallium									.*Gallium.*											1	1	1	2.1
 NVIDIA G100M							.*NVIDIA .*100M.*						4	1	1	3.3
 NVIDIA G102M							.*NVIDIA .*102M.*						1	1	1	3.3
 NVIDIA G103M							.*NVIDIA .*103M.*						2	1	1	3.3
@@ -380,14 +380,14 @@ NVIDIA GTX 660M							.*NVIDIA .*GTX *66*M.*					5	1	0	0
 NVIDIA GTX 670M							.*NVIDIA .*GTX *67*M.*					5	1	1	4.2
 NVIDIA GTX 680M							.*NVIDIA .*GTX *68*M.*					5	1	0	0
 NVIDIA GTX 690M							.*NVIDIA .*GTX *69*M.*					5	1	0	0
-NVIDIA G100								.*NVIDIA .*G10.*						3	1	1	4.2
+NVIDIA G100								.*NVIDIA .*G10.*									3	1	1	4.2
 NVIDIA GT 120							.*NVIDIA .*GT *12.*						2	1	0	3
 NVIDIA GT 130							.*NVIDIA .*GT *13.*						2	1	0	3.3
 NVIDIA GTS 150							.*NVIDIA .*GTS *15.*					2	1	0	0
-NVIDIA 200								.*NVIDIA .*GeForce 20.*					2	1	1	3.3
-NVIDIA G200								.*NVIDIA .*GeForce G20.*				2	1	1	3.3
-NVIDIA G210								.*NVIDIA .*GeForce G210.*				3	1	1	3.3
-NVIDIA 210								.*NVIDIA .*GeForce 210.*				3	1	1	3.3
+NVIDIA 200								.*NVIDIA .*GeForce 20.*								2	1	1	3.3
+NVIDIA G200								.*NVIDIA .*GeForce G20.*							2	1	1	3.3
+NVIDIA G210								.*NVIDIA .*GeForce G210.*							3	1	1	3.3
+NVIDIA 210								.*NVIDIA .*GeForce 210.*							3	1	1	3.3
 NVIDIA GT 220							.*NVIDIA .*GT *22.*						2	1	1	3.3
 NVIDIA GT 230							.*NVIDIA .*GT *23.*						2	1	1	3.3
 NVIDIA GT 240							.*NVIDIA .*GT *24.*						4	1	1	3.3
@@ -397,12 +397,12 @@ NVIDIA GTX 260							.*NVIDIA .*GTX *26.*					4	1	1	3.3
 NVIDIA GTX 270							.*NVIDIA .*GTX *27.*					4	1	0	3.3
 NVIDIA GTX 280							.*NVIDIA .*GTX *28.*					4	1	1	3.3
 NVIDIA GTX 290							.*NVIDIA .*GTX *29.*					5	1	0	3.3
-NVIDIA 310								.*NVIDIA .*GeForce 310.*				3	1	1	3.3
-NVIDIA 315								.*NVIDIA .*GeForce 315.*				3	1	1	3.3
+NVIDIA 310								.*NVIDIA .*GeForce 310.*							3	1	1	3.3
+NVIDIA 315								.*NVIDIA .*GeForce 315.*							3	1	1	3.3
 NVIDIA GT 320							.*NVIDIA .*GT *32.*						3	1	0	3.3
 NVIDIA GT 330							.*NVIDIA .*GT *33.*						3	1	0	3.3
 NVIDIA GT 340							.*NVIDIA .*GT *34.*						3	1	0	0
-NVIDIA 405								.*NVIDIA .* 405.*						3	1	0	3.3
+NVIDIA 405								.*NVIDIA .* 405.*									3	1	0	3.3
 NVIDIA GT 420							.*NVIDIA .*GT *42.*						3	1	1	4.2
 NVIDIA GT 430							.*NVIDIA .*GT *43.*						3	1	1	4.2
 NVIDIA GT 440							.*NVIDIA .*GT *44.*						4	1	0	4.2
@@ -429,125 +429,125 @@ NVIDIA GTX 660							.*NVIDIA .*GTX *66.*					5	1	0	4.3
 NVIDIA GTX 670							.*NVIDIA .*GTX *67.*					5	1	1	4.2
 NVIDIA GTX 680							.*NVIDIA .*GTX *68.*					5	1	1	4.2
 NVIDIA GTX 690							.*NVIDIA .*GTX *69.*					5	1	1	4.2
-NVIDIA C51								.*NVIDIA .*C51.*						0	1	1	2
-NVIDIA G72								.*NVIDIA .*G72.*						1	1	0	0
-NVIDIA G73								.*NVIDIA .*G73.*						1	1	0	0
-NVIDIA G84								.*NVIDIA .*G84.*						2	1	0	0
-NVIDIA G86								.*NVIDIA .*G86.*						3	1	0	0
-NVIDIA G92								.*NVIDIA .*G92.*						3	1	0	0
-NVIDIA GeForce							.*GeForce 256.*							0	0	0	0
-NVIDIA GeForce 2						.*GeForce ?2 ?.*						0	1	1	1.5
+NVIDIA C51								.*NVIDIA .*C51.*									0	1	1	2
+NVIDIA G72								.*NVIDIA .*G72.*									1	1	0	0
+NVIDIA G73								.*NVIDIA .*G73.*									1	1	0	0
+NVIDIA G84								.*NVIDIA .*G84.*									2	1	0	0
+NVIDIA G86								.*NVIDIA .*G86.*									3	1	0	0
+NVIDIA G92								.*NVIDIA .*G92.*									3	1	0	0
+NVIDIA GeForce							.*GeForce 256.*										0	0	0	0
+NVIDIA GeForce 2						.*GeForce ?2 ?.*									0	1	1	1.5
 NVIDIA GeForce 3						.*GeForce ?3 ?.*						2	1	1	2.1
 NVIDIA GeForce 3 Ti						.*GeForce ?3 Ti.*						0	1	0	0
-NVIDIA GeForce 4						.*NVIDIA .*GeForce ?4.*					0	1	1	1.5
+NVIDIA GeForce 4						.*NVIDIA .*GeForce ?4.*								0	1	1	1.5
 NVIDIA GeForce 4 Go						.*NVIDIA .*GeForce ?4.*Go.*				0	1	0	0
 NVIDIA GeForce 4 MX						.*NVIDIA .*GeForce ?4 MX.*				0	1	0	0
 NVIDIA GeForce 4 PCX					.*NVIDIA .*GeForce ?4 PCX.*				0	1	0	0
 NVIDIA GeForce 4 Ti						.*NVIDIA .*GeForce ?4 Ti.*				0	1	0	0
-NVIDIA GeForce 6100						.*NVIDIA .*GeForce 61.*					3	1	1	4.2
-NVIDIA GeForce 6200						.*NVIDIA .*GeForce 62.*					0	1	1	2.1
-NVIDIA GeForce 6500						.*NVIDIA .*GeForce 65.*					1	1	1	2.1
-NVIDIA GeForce 6600						.*NVIDIA .*GeForce 66.*					2	1	1	2.1
-NVIDIA GeForce 6700						.*NVIDIA .*GeForce 67.*					2	1	1	2.1
-NVIDIA GeForce 6800						.*NVIDIA .*GeForce 68.*					1	1	1	2.1
-NVIDIA GeForce 7000						.*NVIDIA .*GeForce 70.*					1	1	1	2.1
-NVIDIA GeForce 7100						.*NVIDIA .*GeForce 71.*					1	1	1	2.1
-NVIDIA GeForce 7200						.*NVIDIA .*GeForce 72.*					1	1	0	0
-NVIDIA GeForce 7300						.*NVIDIA .*GeForce 73.*					1	1	1	2.1
-NVIDIA GeForce 7500						.*NVIDIA .*GeForce 75.*					2	1	1	2.1
-NVIDIA GeForce 7600						.*NVIDIA .*GeForce 76.*					2	1	1	2.1
-NVIDIA GeForce 7800						.*NVIDIA .*GeForce 78.*					2	1	1	2.1
-NVIDIA GeForce 7900						.*NVIDIA .*GeForce 79.*					3	1	1	2.1
+NVIDIA GeForce 6100						.*NVIDIA .*GeForce 61.*								3	1	1	4.2
+NVIDIA GeForce 6200						.*NVIDIA .*GeForce 62.*								0	1	1	2.1
+NVIDIA GeForce 6500						.*NVIDIA .*GeForce 65.*								1	1	1	2.1
+NVIDIA GeForce 6600						.*NVIDIA .*GeForce 66.*								2	1	1	2.1
+NVIDIA GeForce 6700						.*NVIDIA .*GeForce 67.*								2	1	1	2.1
+NVIDIA GeForce 6800						.*NVIDIA .*GeForce 68.*								1	1	1	2.1
+NVIDIA GeForce 7000						.*NVIDIA .*GeForce 70.*								1	1	1	2.1
+NVIDIA GeForce 7100						.*NVIDIA .*GeForce 71.*								1	1	1	2.1
+NVIDIA GeForce 7200						.*NVIDIA .*GeForce 72.*								1	1	0	0
+NVIDIA GeForce 7300						.*NVIDIA .*GeForce 73.*								1	1	1	2.1
+NVIDIA GeForce 7500						.*NVIDIA .*GeForce 75.*								2	1	1	2.1
+NVIDIA GeForce 7600						.*NVIDIA .*GeForce 76.*								2	1	1	2.1
+NVIDIA GeForce 7800						.*NVIDIA .*GeForce 78.*								2	1	1	2.1
+NVIDIA GeForce 7900						.*NVIDIA .*GeForce 79.*								3	1	1	2.1
 NVIDIA GeForce 8100						.*NVIDIA .*GeForce 81.*					1	1	0	0
 NVIDIA GeForce 8200M					.*NVIDIA .*GeForce 8200M.*				1	1	0	3.3
 NVIDIA GeForce 8200						.*NVIDIA .*GeForce 82.*					1	1	0	2.1
-NVIDIA GeForce 8300						.*NVIDIA .*GeForce 83.*					3	1	1	3.3
+NVIDIA GeForce 8300						.*NVIDIA .*GeForce 83.*								3	1	1	3.3
 NVIDIA GeForce 8400M					.*NVIDIA .*GeForce 8400M.*				1	1	1	3.3
-NVIDIA GeForce 8400						.*NVIDIA .*GeForce 84.*					2	1	1	3.3
-NVIDIA GeForce 8500						.*NVIDIA .*GeForce 85.*					2	1	1	3.3
+NVIDIA GeForce 8400						.*NVIDIA .*GeForce 84.*								2	1	1	3.3
+NVIDIA GeForce 8500						.*NVIDIA .*GeForce 85.*								2	1	1	3.3
 NVIDIA GeForce 8600M					.*NVIDIA .*GeForce 8600M.*				2	1	1	3.3
-NVIDIA GeForce 8600						.*NVIDIA .*GeForce 86.*					3	1	1	3.3
+NVIDIA GeForce 8600						.*NVIDIA .*GeForce 86.*								3	1	1	3.3
 NVIDIA GeForce 8700M					.*NVIDIA .*GeForce 8700M.*				2	1	1	3.3
-NVIDIA GeForce 8700						.*NVIDIA .*GeForce 87.*					3	1	0	0
+NVIDIA GeForce 8700						.*NVIDIA .*GeForce 87.*								3	1	0	0
 NVIDIA GeForce 8800M					.*NVIDIA .*GeForce 8800M.*				2	1	1	3.3
-NVIDIA GeForce 8800						.*NVIDIA .*GeForce 88.*					3	1	1	3.3
+NVIDIA GeForce 8800						.*NVIDIA .*GeForce 88.*								3	1	1	3.3
 NVIDIA GeForce 9100M					.*NVIDIA .*GeForce 9100M.*				0	1	0	0
-NVIDIA GeForce 9100						.*NVIDIA .*GeForce 91.*					0	1	0	3.3
+NVIDIA GeForce 9100						.*NVIDIA .*GeForce 91.*								0	1	0	3.3
 NVIDIA GeForce 9200M					.*NVIDIA .*GeForce 9200M.*				1	1	0	3.1
-NVIDIA GeForce 9200						.*NVIDIA .*GeForce 92.*					1	1	0	3.3
+NVIDIA GeForce 9200						.*NVIDIA .*GeForce 92.*								1	1	0	3.3
 NVIDIA GeForce 9300M					.*NVIDIA .*GeForce 9300M.*				1	1	1	3.3
-NVIDIA GeForce 9300						.*NVIDIA .*GeForce 93.*					1	1	1	3.3
+NVIDIA GeForce 9300						.*NVIDIA .*GeForce 93.*								1	1	1	3.3
 NVIDIA GeForce 9400M					.*NVIDIA .*GeForce 9400M.*				2	1	1	3.3
-NVIDIA GeForce 9400						.*NVIDIA .*GeForce 94.*					3	1	1	3.3
+NVIDIA GeForce 9400						.*NVIDIA .*GeForce 94.*								3	1	1	3.3
 NVIDIA GeForce 9500M					.*NVIDIA .*GeForce 9500M.*				1	1	1	3.3
-NVIDIA GeForce 9500						.*NVIDIA .*GeForce 95.*					3	1	1	3.3
+NVIDIA GeForce 9500						.*NVIDIA .*GeForce 95.*								3	1	1	3.3
 NVIDIA GeForce 9600M					.*NVIDIA .*GeForce 9600M.*				2	1	1	3.3
-NVIDIA GeForce 9600						.*NVIDIA .*GeForce 96.*					3	1	1	3.3
+NVIDIA GeForce 9600						.*NVIDIA .*GeForce 96.*								3	1	1	3.3
 NVIDIA GeForce 9700M					.*NVIDIA .*GeForce 9700M.*				0	1	1	3.3
 NVIDIA GeForce 9800M					.*NVIDIA .*GeForce 9800M.*				2	1	1	3.3
-NVIDIA GeForce 9800						.*NVIDIA .*GeForce 98.*					3	1	1	3.3
-NVIDIA GeForce FX 5100					.*NVIDIA .*GeForce FX 51.*				0	1	0	0
-NVIDIA GeForce FX 5200					.*NVIDIA .*GeForce FX 52.*				0	1	0	2.1
-NVIDIA GeForce FX 5300					.*NVIDIA .*GeForce FX 53.*				0	1	0	0
-NVIDIA GeForce FX 5500					.*NVIDIA .*GeForce FX 55.*				0	1	1	2.1
-NVIDIA GeForce FX 5600					.*NVIDIA .*GeForce FX 56.*				1	1	1	2.1
-NVIDIA GeForce FX 5700					.*NVIDIA .*GeForce FX 57.*				0	1	1	2.1
-NVIDIA GeForce FX 5800					.*NVIDIA .*GeForce FX 58.*				1	1	0	0
-NVIDIA GeForce FX 5900					.*NVIDIA .*GeForce FX 59.*				1	1	1	2.1
-NVIDIA GeForce FX Go5100				.*NVIDIA .*GeForce FX Go51.*			0	1	0	0
+NVIDIA GeForce 9800						.*NVIDIA .*GeForce 98.*								3	1	1	3.3
+NVIDIA GeForce FX 5100					.*NVIDIA .*GeForce FX 51.*							0	1	0	0
+NVIDIA GeForce FX 5200					.*NVIDIA .*GeForce FX 52.*							0	1	0	2.1
+NVIDIA GeForce FX 5300					.*NVIDIA .*GeForce FX 53.*							0	1	0	0
+NVIDIA GeForce FX 5500					.*NVIDIA .*GeForce FX 55.*							0	1	1	2.1
+NVIDIA GeForce FX 5600					.*NVIDIA .*GeForce FX 56.*							1	1	1	2.1
+NVIDIA GeForce FX 5700					.*NVIDIA .*GeForce FX 57.*							0	1	1	2.1
+NVIDIA GeForce FX 5800					.*NVIDIA .*GeForce FX 58.*							1	1	0	0
+NVIDIA GeForce FX 5900					.*NVIDIA .*GeForce FX 59.*							1	1	1	2.1
+NVIDIA GeForce FX Go5100				.*NVIDIA .*GeForce FX Go51.*						0	1	0	0
 NVIDIA GeForce FX Go5200				.*NVIDIA .*GeForce FX Go52.*			0	1	0	0
-NVIDIA GeForce FX Go5300				.*NVIDIA .*GeForce FX Go53.*			0	1	0	0
-NVIDIA GeForce FX Go5500				.*NVIDIA .*GeForce FX Go55.*			0	1	0	0
-NVIDIA GeForce FX Go5600				.*NVIDIA .*GeForce FX Go56.*			0	1	1	2.1
-NVIDIA GeForce FX Go5700				.*NVIDIA .*GeForce FX Go57.*			1	1	1	1.5
-NVIDIA GeForce FX Go5800				.*NVIDIA .*GeForce FX Go58.*			1	1	0	0
-NVIDIA GeForce FX Go5900				.*NVIDIA .*GeForce FX Go59.*			1	1	0	0
-NVIDIA GeForce FX Go5xxx				.*NVIDIA .*GeForce FX Go.*				0	1	0	0
-NVIDIA GeForce Go 6100					.*NVIDIA .*GeForce Go 61.*				0	1	1	2.1
+NVIDIA GeForce FX Go5300				.*NVIDIA .*GeForce FX Go53.*						0	1	0	0
+NVIDIA GeForce FX Go5500				.*NVIDIA .*GeForce FX Go55.*						0	1	0	0
+NVIDIA GeForce FX Go5600				.*NVIDIA .*GeForce FX Go56.*						0	1	1	2.1
+NVIDIA GeForce FX Go5700				.*NVIDIA .*GeForce FX Go57.*						1	1	1	1.5
+NVIDIA GeForce FX Go5800				.*NVIDIA .*GeForce FX Go58.*						1	1	0	0
+NVIDIA GeForce FX Go5900				.*NVIDIA .*GeForce FX Go59.*						1	1	0	0
+NVIDIA GeForce FX Go5xxx				.*NVIDIA .*GeForce FX Go.*							0	1	0	0
+NVIDIA GeForce Go 6100					.*NVIDIA .*GeForce Go 61.*							0	1	1	2.1
 NVIDIA GeForce Go 6200					.*NVIDIA .*GeForce Go 62.*				0	1	0	0
 NVIDIA GeForce Go 6400					.*NVIDIA .*GeForce Go 64.*				1	1	1	2
-NVIDIA GeForce Go 6500					.*NVIDIA .*GeForce Go 65.*				1	1	0	0
-NVIDIA GeForce Go 6600					.*NVIDIA .*GeForce Go 66.*				0	1	1	2.1
-NVIDIA GeForce Go 6700					.*NVIDIA .*GeForce Go 67.*				1	1	0	0
-NVIDIA GeForce Go 6800					.*NVIDIA .*GeForce Go 68.*				0	1	1	2.1
+NVIDIA GeForce Go 6500					.*NVIDIA .*GeForce Go 65.*							1	1	0	0
+NVIDIA GeForce Go 6600					.*NVIDIA .*GeForce Go 66.*							0	1	1	2.1
+NVIDIA GeForce Go 6700					.*NVIDIA .*GeForce Go 67.*							1	1	0	0
+NVIDIA GeForce Go 6800					.*NVIDIA .*GeForce Go 68.*							0	1	1	2.1
 NVIDIA GeForce Go 7200					.*NVIDIA .*GeForce Go 72.*				1	1	0	0
-NVIDIA GeForce Go 7300 LE				.*NVIDIA .*GeForce Go 73.*LE.*			1	1	0	0
-NVIDIA GeForce Go 7300					.*NVIDIA .*GeForce Go 73.*				1	1	1	2.1
-NVIDIA GeForce Go 7400					.*NVIDIA .*GeForce Go 74.*				1	1	1	2.1
-NVIDIA GeForce Go 7600					.*NVIDIA .*GeForce Go 76.*				1	1	1	2.1
-NVIDIA GeForce Go 7700					.*NVIDIA .*GeForce Go 77.*				0	1	1	2.1
-NVIDIA GeForce Go 7800					.*NVIDIA .*GeForce Go 78.*				2	1	0	0
-NVIDIA GeForce Go 7900					.*NVIDIA .*GeForce Go 79.*				1	1	1	2.1
-NVIDIA D9M								.*NVIDIA .*D9M.*						1	1	0	0
-NVIDIA G94								.*NVIDIA .*G94.*						3	1	0	0
-NVIDIA GeForce Go 6						.*GeForce Go 6.*						1	1	0	0
-NVIDIA ION 2							.*NVIDIA .*ION 2.*						2	1	0	0
-NVIDIA ION 								.*NVIDIA Corporation.*ION.*				2	1	1	3.3
-NVIDIA NB8M								.*NVIDIA .*NB8M.*						1	1	0	0
-NVIDIA NB8P								.*NVIDIA .*NB8P.*						2	1	0	0
-NVIDIA NB9E								.*NVIDIA .*NB9E.*						3	1	0	0
-NVIDIA NB9M								.*NVIDIA .*NB9M.*						1	1	0	0
-NVIDIA NB9P								.*NVIDIA .*NB9P.*						2	1	0	0
+NVIDIA GeForce Go 7300 LE				.*NVIDIA .*GeForce Go 73.*LE.*						1	1	0	0
+NVIDIA GeForce Go 7300					.*NVIDIA .*GeForce Go 73.*							1	1	1	2.1
+NVIDIA GeForce Go 7400					.*NVIDIA .*GeForce Go 74.*							1	1	1	2.1
+NVIDIA GeForce Go 7600					.*NVIDIA .*GeForce Go 76.*							1	1	1	2.1
+NVIDIA GeForce Go 7700					.*NVIDIA .*GeForce Go 77.*							0	1	1	2.1
+NVIDIA GeForce Go 7800					.*NVIDIA .*GeForce Go 78.*							2	1	0	0
+NVIDIA GeForce Go 7900					.*NVIDIA .*GeForce Go 79.*							1	1	1	2.1
+NVIDIA D9M								.*NVIDIA .*D9M.*									1	1	0	0
+NVIDIA G94								.*NVIDIA .*G94.*									3	1	0	0
+NVIDIA GeForce Go 6						.*GeForce Go 6.*									1	1	0	0
+NVIDIA ION 2							.*NVIDIA .*ION 2.*									2	1	0	0
+NVIDIA ION 								.*NVIDIA Corporation.*ION.*							2	1	1	3.3
+NVIDIA NB8M								.*NVIDIA .*NB8M.*									1	1	0	0
+NVIDIA NB8P								.*NVIDIA .*NB8P.*									2	1	0	0
+NVIDIA NB9E								.*NVIDIA .*NB9E.*									3	1	0	0
+NVIDIA NB9M								.*NVIDIA .*NB9M.*									1	1	0	0
+NVIDIA NB9P								.*NVIDIA .*NB9P.*									2	1	0	0
 NVIDIA N10								.*NVIDIA .*N10.*						1	1	0	0
 NVIDIA GeForce PCX						.*GeForce PCX.*							0	1	0	0
 NVIDIA Generic							.*NVIDIA .*Unknown.*					0	0	0	3
-NVIDIA NV17								.*NVIDIA .*NV17.*						0	1	0	0
-NVIDIA NV34								.*NVIDIA .*NV34.*						0	1	0	0
-NVIDIA NV35								.*NVIDIA .*NV35.*						0	1	0	0
-NVIDIA NV36								.*NVIDIA .*NV36.*						1	1	0	0
-NVIDIA NV41								.*NVIDIA .*NV41.*						1	1	0	0
-NVIDIA NV43								.*NVIDIA .*NV43.*						1	1	0	0
-NVIDIA NV44								.*NVIDIA .*NV44.*						1	1	0	0
-NVIDIA nForce							.*NVIDIA .*nForce.*						0	0	0	3.3
-NVIDIA MCP51							.*NVIDIA .*MCP51.*						1	1	0	0
+NVIDIA NV17								.*NVIDIA .*NV17.*									0	1	0	0
+NVIDIA NV34								.*NVIDIA .*NV34.*									0	1	0	0
+NVIDIA NV35								.*NVIDIA .*NV35.*									0	1	0	0
+NVIDIA NV36								.*NVIDIA .*NV36.*									1	1	0	0
+NVIDIA NV41								.*NVIDIA .*NV41.*									1	1	0	0
+NVIDIA NV43								.*NVIDIA .*NV43.*									1	1	0	0
+NVIDIA NV44								.*NVIDIA .*NV44.*									1	1	0	0
+NVIDIA nForce							.*NVIDIA .*nForce.*									0	0	0	3.3
+NVIDIA MCP51							.*NVIDIA .*MCP51.*									1	1	0	0
 NVIDIA MCP61							.*NVIDIA .*MCP61.*						1	1	0	0
-NVIDIA MCP67							.*NVIDIA .*MCP67.*						1	1	0	0
-NVIDIA MCP68							.*NVIDIA .*MCP68.*						1	1	0	0
-NVIDIA MCP73							.*NVIDIA .*MCP73.*						1	1	0	0
-NVIDIA MCP77							.*NVIDIA .*MCP77.*						1	1	0	0
-NVIDIA MCP78							.*NVIDIA .*MCP78.*						1	1	0	0
-NVIDIA MCP79							.*NVIDIA .*MCP79.*						1	1	0	0
-NVIDIA MCP7A							.*NVIDIA .*MCP7A.*						1	1	0	0
+NVIDIA MCP67							.*NVIDIA .*MCP67.*									1	1	0	0
+NVIDIA MCP68							.*NVIDIA .*MCP68.*									1	1	0	0
+NVIDIA MCP73							.*NVIDIA .*MCP73.*									1	1	0	0
+NVIDIA MCP77							.*NVIDIA .*MCP77.*									1	1	0	0
+NVIDIA MCP78							.*NVIDIA .*MCP78.*									1	1	0	0
+NVIDIA MCP79							.*NVIDIA .*MCP79.*									1	1	0	0
+NVIDIA MCP7A							.*NVIDIA .*MCP7A.*									1	1	0	0
 NVIDIA Quadro2							.*Quadro2.*								0	1	0	0
 NVIDIA Quadro 1000M						.*Quadro.*1000M.*						2	1	0	4.2
 NVIDIA Quadro 2000 M/D					.*Quadro.*2000.*						3	1	0	4.2
@@ -555,12 +555,12 @@ NVIDIA Quadro 3000M						.*Quadro.*3000M.*						3	1	0	0
 NVIDIA Quadro 4000M						.*Quadro.*4000M.*						3	1	0	0
 NVIDIA Quadro 4000						.*Quadro *4000.*						3	1	0	4.2
 NVIDIA Quadro 50x0 M					.*Quadro.*50.0.*						3	1	0	0
-NVIDIA Quadro 6000						.*Quadro.*6000.*						3	1	0	0
-NVIDIA Quadro 400						.*Quadro.*400.*							2	1	0	3.3
+NVIDIA Quadro 6000						.*Quadro.* 6000.*									3	1	0	0
+NVIDIA Quadro 400						.*Quadro.* 400.*									2	1	0	3.3
 NVIDIA Quadro 600						.*Quadro.*600.*							2	1	0	3.3
 NVIDIA Quadro4							.*Quadro4.*								0	1	0	0
-NVIDIA Quadro DCC						.*Quadro DCC.*							0	1	0	0
-NVIDIA Quadro CX						.*Quadro.*CX.*							3	1	0	0
+NVIDIA Quadro DCC						.*Quadro DCC.*										0	1	0	0
+NVIDIA Quadro CX						.*Quadro.*CX.*										3	1	0	0
 NVIDIA Quadro FX 770M					.*Quadro.*FX *770M.*					2	1	0	0
 NVIDIA Quadro FX 1500M					.*Quadro.*FX *1500M.*					1	1	0	2.1
 NVIDIA Quadro FX 1600M					.*Quadro.*FX *1600M.*					2	1	0	0
@@ -574,7 +574,7 @@ NVIDIA Quadro FX 3800					.*Quadro.*FX *3800.*					3	1	0	3.2
 NVIDIA Quadro FX 4500					.*Quadro.*FX *45.*						3	1	0	0
 NVIDIA Quadro FX 880M					.*Quadro.*FX *880M.*					3	1	0	3.3
 NVIDIA Quadro FX 4800					.*NVIDIA .*Quadro *FX *4800.*			3	1	0	0
-NVIDIA Quadro FX						.*Quadro FX.*							1	1	0	3.3
+NVIDIA Quadro FX						.*Quadro FX.*										1	1	0	3.3
 NVIDIA Quadro NVS 1xxM					.*Quadro NVS *1.[05]M.*					0	1	1	3.3
 NVIDIA Quadro NVS 300M					.*NVIDIA .*NVS *300M.*					2	1	0	0
 NVIDIA Quadro NVS 320M					.*NVIDIA .*NVS *320M.*					2	1	0	0
@@ -583,16 +583,16 @@ NVIDIA Quadro NVS 3100M					.*NVIDIA .*NVS *3100M.*					2	1	0	0
 NVIDIA Quadro NVS 4200M					.*NVIDIA .*NVS *4200M.*					2	1	0	4.1
 NVIDIA Quadro NVS 5100M					.*NVIDIA .*NVS *5100M.*					2	1	0	0
 NVIDIA Quadro NVS						.*NVIDIA .*NVS							0	1	0	3.2
-NVIDIA Corporation N12P					.*NVIDIA .*N12P.*						1	1	1	4.1
+NVIDIA Corporation N12P					.*NVIDIA .*N12P.*									1	1	1	4.1
 NVIDIA Corporation N11M					.*NVIDIA .*N11M.*						2	1	0	0
 NVIDIA RIVA TNT							.*RIVA TNT.*							0	0	0	0
-S3										.*S3 Graphics.*							0	0	1	1.4
-SiS										SiS.*									0	0	1	1.5
-Trident									Trident.*								0	0	0	0
-Tungsten Graphics						Tungsten.*								0	0	0	0
-XGI										XGI.*									0	0	0	0
-VIA										VIA.*									0	0	0	0
-Apple Generic							Apple.*Generic.*						0	0	0	0
-Apple Software Renderer					Apple.*Software Renderer.*				0	0	0	0
-Humper									Humper.*								0	1	1	2.1
-PowerVR SGX545							.*PowerVR SGX.*							1	1	1	3
+S3										.*S3 Graphics.*										0	0	1	1.4
+SiS										SiS.*												0	0	1	1.5
+Trident									Trident.*											0	0	0	0
+Tungsten Graphics						Tungsten.*											0	0	0	0
+XGI										XGI.*												0	0	0	0
+VIA										VIA.*												0	0	0	0
+Apple Generic							Apple.*Generic.*									0	0	0	0
+Apple Software Renderer					Apple.*Software Renderer.*							0	0	0	0
+Humper									Humper.*											0	1	1	2.1
+PowerVR SGX545							.*PowerVR SGX.*										1	1	1	3
diff --git a/indra/newview/llagent.cpp b/indra/newview/llagent.cpp
index 8c42defa73f25bc7a47871ffd8911b7b54848403..3e94c5edf758ade2e383e3f2bf00aea8ddfbb541 100755
--- a/indra/newview/llagent.cpp
+++ b/indra/newview/llagent.cpp
@@ -4317,7 +4317,7 @@ void LLAgent::sendAgentSetAppearance()
 		return;
 	}
 	
-
+	
 	LL_DEBUGS("Avatar") << gAgentAvatarp->avString() << "TAT: Sent AgentSetAppearance: " << gAgentAvatarp->getBakedStatusForPrintout() << LL_ENDL;
 	//dumpAvatarTEs( "sendAgentSetAppearance()" );
 
@@ -4425,7 +4425,7 @@ void LLAgent::sendAgentSetAppearance()
 		}
 	}
 
-	//llinfos << "Avatar XML num VisualParams transmitted = " << transmitted_params << llendl;
+//	llinfos << "Avatar XML num VisualParams transmitted = " << transmitted_params << llendl;
 	sendReliableMessage();
 }
 
diff --git a/indra/newview/llagentcamera.cpp b/indra/newview/llagentcamera.cpp
index 0896aa5972467beedf965b9318826ab5df116e99..488a134aa24d008fc6cca74fdd3f708f75be5b89 100755
--- a/indra/newview/llagentcamera.cpp
+++ b/indra/newview/llagentcamera.cpp
@@ -2267,22 +2267,22 @@ void LLAgentCamera::changeCameraToCustomizeAvatar()
 		gFocusMgr.setKeyboardFocus( NULL );
 		gFocusMgr.setMouseCapture( NULL );
 
-		// Remove any pitch or rotation from the avatar
-		LLVector3 at = gAgent.getAtAxis();
-		at.mV[VZ] = 0.f;
-		at.normalize();
-		gAgent.resetAxes(at);
-
-		gAgent.sendAnimationRequest(ANIM_AGENT_CUSTOMIZE, ANIM_REQUEST_START);
-		gAgent.setCustomAnim(TRUE);
-		gAgentAvatarp->startMotion(ANIM_AGENT_CUSTOMIZE);
-		LLMotion* turn_motion = gAgentAvatarp->findMotion(ANIM_AGENT_CUSTOMIZE);
-
-		if (turn_motion)
-		{
-			// delay camera animation long enough to play through turn animation
-			setAnimationDuration(turn_motion->getDuration() + CUSTOMIZE_AVATAR_CAMERA_ANIM_SLOP);
-		}
+			// Remove any pitch or rotation from the avatar
+			LLVector3 at = gAgent.getAtAxis();
+			at.mV[VZ] = 0.f;
+			at.normalize();
+			gAgent.resetAxes(at);
+
+			gAgent.sendAnimationRequest(ANIM_AGENT_CUSTOMIZE, ANIM_REQUEST_START);
+			gAgent.setCustomAnim(TRUE);
+			gAgentAvatarp->startMotion(ANIM_AGENT_CUSTOMIZE);
+			LLMotion* turn_motion = gAgentAvatarp->findMotion(ANIM_AGENT_CUSTOMIZE);
+
+			if (turn_motion)
+			{
+				// delay camera animation long enough to play through turn animation
+				setAnimationDuration(turn_motion->getDuration() + CUSTOMIZE_AVATAR_CAMERA_ANIM_SLOP);
+			}
 	}
 
 	LLVector3 agent_at = gAgent.getAtAxis();
diff --git a/indra/newview/llagentwearables.cpp b/indra/newview/llagentwearables.cpp
index c88694ef76b9054cfbe20543c33027a4681c0d07..1edbbe2a2e8cf4ca6f49a7a817b99796fc5d7f96 100755
--- a/indra/newview/llagentwearables.cpp
+++ b/indra/newview/llagentwearables.cpp
@@ -62,15 +62,15 @@ using namespace LLAvatarAppearanceDefines;
 
 // Callback to wear and start editing an item that has just been created.
 void wear_and_edit_cb(const LLUUID& inv_item)
-{
-	if (inv_item.isNull()) return;
-	
-	// Request editing the item after it gets worn.
-	gAgentWearables.requestEditingWearable(inv_item);
-	
-	// Wear it.
-	LLAppearanceMgr::instance().wearItemOnAvatar(inv_item);
-}
+	{
+		if (inv_item.isNull()) return;
+
+		// Request editing the item after it gets worn.
+		gAgentWearables.requestEditingWearable(inv_item);
+
+		// Wear it.
+		LLAppearanceMgr::instance().wearItemOnAvatar(inv_item);
+	}
 
 ///////////////////////////////////////////////////////////////////////////////
 
@@ -180,10 +180,10 @@ void LLAgentWearables::initClass()
 }
 
 void LLAgentWearables::setAvatarObject(LLVOAvatarSelf *avatar)
-{
+{ 
 	llassert(avatar);
-	avatar->outputRezTiming("Sending wearables request");
-	sendAgentWearablesRequest();
+		avatar->outputRezTiming("Sending wearables request");
+		sendAgentWearablesRequest();
 	setAvatarAppearance(avatar);
 }
 
@@ -706,7 +706,7 @@ LLViewerWearable* LLAgentWearables::getViewerWearable(const LLWearableType::ETyp
 }
 
 const LLViewerWearable* LLAgentWearables::getViewerWearable(const LLWearableType::EType type, U32 index /*= 0*/) const
-{
+	{
 	return dynamic_cast<const LLViewerWearable*> (getWearable(type, index));
 }
 
@@ -714,39 +714,39 @@ const LLViewerWearable* LLAgentWearables::getViewerWearable(const LLWearableType
 BOOL LLAgentWearables::selfHasWearable(LLWearableType::EType type)
 {
 	return (gAgentWearables.getWearableCount(type) > 0);
-}
-
+	}
+	
 // virtual
 void LLAgentWearables::wearableUpdated(LLWearable *wearable, BOOL removed)
-{
+	{
 	if (isAgentAvatarValid())
 	{
 		const BOOL upload_result = removed;
 		gAgentAvatarp->wearableUpdated(wearable->getType(), upload_result);
-	}
+}
 
 	LLWearableData::wearableUpdated(wearable, removed);
 
 	if (!removed)
-	{
+{
 		LLViewerWearable* viewer_wearable = dynamic_cast<LLViewerWearable*>(wearable);
 		viewer_wearable->refreshName();
 
-		// Hack pt 2. If the wearable we just loaded has definition version 24,
-		// then force a re-save of this wearable after slamming the version number to 22.
-		// This number was incorrectly incremented for internal builds before release, and
-		// this fix will ensure that the affected wearables are re-saved with the right version number.
-		// the versions themselves are compatible. This code can be removed before release.
-		if( wearable->getDefinitionVersion() == 24 )
-		{
-			wearable->setDefinitionVersion(22);
-			U32 index = getWearableIndex(wearable);
+	// Hack pt 2. If the wearable we just loaded has definition version 24,
+	// then force a re-save of this wearable after slamming the version number to 22.
+	// This number was incorrectly incremented for internal builds before release, and
+	// this fix will ensure that the affected wearables are re-saved with the right version number.
+	// the versions themselves are compatible. This code can be removed before release.
+	if( wearable->getDefinitionVersion() == 24 )
+	{
+		wearable->setDefinitionVersion(22);
+		U32 index = getWearableIndex(wearable);
 			llinfos << "forcing wearable type " << wearable->getType() << " to version 22 from 24" << llendl;
-			saveWearable(wearable->getType(),index,TRUE);
-		}
+		saveWearable(wearable->getType(),index,TRUE);
+	}
 
 		checkWearableAgainstInventory(viewer_wearable);
-	}
+}
 }
 
 BOOL LLAgentWearables::itemUpdatePending(const LLUUID& item_id) const
@@ -965,8 +965,8 @@ class OnWearableItemCreatedCB: public LLInventoryCallback
 		llinfos << "All items created" << llendl;
 		LLPointer<LLInventoryCallback> link_waiter = new LLUpdateAppearanceOnDestroy;
 		LLAppearanceMgr::instance().linkAll(LLAppearanceMgr::instance().getCOF(),
-											mItemsToLink,
-											link_waiter);
+												mItemsToLink,
+												link_waiter);
 	}
 	void addPendingWearable(LLViewerWearable *wearable)
 	{
@@ -1496,12 +1496,12 @@ void LLAgentWearables::queryWearableCache()
 // virtual
 void LLAgentWearables::invalidateBakedTextureHash(LLMD5& hash) const
 {
-	// Add some garbage into the hash so that it becomes invalid.
-	if (isAgentAvatarValid())
-	{
-		hash.update((const unsigned char*)gAgentAvatarp->getID().mData, UUID_BYTES);
-	}
-}
+		// Add some garbage into the hash so that it becomes invalid.
+			if (isAgentAvatarValid())
+			{
+				hash.update((const unsigned char*)gAgentAvatarp->getID().mData, UUID_BYTES);
+			}
+		}
 
 // User has picked "remove from avatar" from a menu.
 // static
diff --git a/indra/newview/llagentwearablesfetch.cpp b/indra/newview/llagentwearablesfetch.cpp
index 2d2d730396bc9583311d0e162ef9eff44d251f2b..8b6b6db525058d2547a04262d55deffaf41e27f1 100755
--- a/indra/newview/llagentwearablesfetch.cpp
+++ b/indra/newview/llagentwearablesfetch.cpp
@@ -36,44 +36,44 @@
 
 
 void order_my_outfits_cb()
-{
-	if (!LLApp::isRunning())
 	{
-		llwarns << "called during shutdown, skipping" << llendl;
-		return;
-	}
+		if (!LLApp::isRunning())
+		{
+			llwarns << "called during shutdown, skipping" << llendl;
+			return;
+		}
 		
-	const LLUUID& my_outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
-	if (my_outfits_id.isNull()) return;
+		const LLUUID& my_outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS);
+		if (my_outfits_id.isNull()) return;
 
-	LLInventoryModel::cat_array_t* cats;
-	LLInventoryModel::item_array_t* items;
-	gInventory.getDirectDescendentsOf(my_outfits_id, cats, items);
-	if (!cats) return;
+		LLInventoryModel::cat_array_t* cats;
+		LLInventoryModel::item_array_t* items;
+		gInventory.getDirectDescendentsOf(my_outfits_id, cats, items);
+		if (!cats) return;
 
-	//My Outfits should at least contain saved initial outfit and one another outfit
-	if (cats->size() < 2)
-	{
-		llwarning("My Outfits category was not populated properly", 0);
-		return;
-	}
+		//My Outfits should at least contain saved initial outfit and one another outfit
+		if (cats->size() < 2)
+		{
+			llwarning("My Outfits category was not populated properly", 0);
+			return;
+		}
 
-	llinfos << "Starting updating My Outfits with wearables ordering information" << llendl;
+		llinfos << "Starting updating My Outfits with wearables ordering information" << llendl;
 
-	for (LLInventoryModel::cat_array_t::iterator outfit_iter = cats->begin();
-		 outfit_iter != cats->end(); ++outfit_iter)
-	{
-		const LLUUID& cat_id = (*outfit_iter)->getUUID();
-		if (cat_id.isNull()) continue;
+		for (LLInventoryModel::cat_array_t::iterator outfit_iter = cats->begin();
+			outfit_iter != cats->end(); ++outfit_iter)
+		{
+			const LLUUID& cat_id = (*outfit_iter)->getUUID();
+			if (cat_id.isNull()) continue;
 
-		// saved initial outfit already contains wearables ordering information
-		if (cat_id == LLAppearanceMgr::getInstance()->getBaseOutfitUUID()) continue;
+			// saved initial outfit already contains wearables ordering information
+			if (cat_id == LLAppearanceMgr::getInstance()->getBaseOutfitUUID()) continue;
 
-		LLAppearanceMgr::getInstance()->updateClothingOrderingInfo(cat_id);
-	}
+			LLAppearanceMgr::getInstance()->updateClothingOrderingInfo(cat_id);
+		}
 
-	llinfos << "Finished updating My Outfits with wearables ordering information" << llendl;
-}
+		llinfos << "Finished updating My Outfits with wearables ordering information" << llendl;
+	}
 
 LLInitialWearablesFetch::LLInitialWearablesFetch(const LLUUID& cof_id) :
 	LLInventoryFetchDescendentsObserver(cof_id)
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index 652f199e2835686dbe4426cd4a47ac41bbe782b4..fd9236c8b384cf6403edb779c320396cc1a80e04 100755
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -196,7 +196,7 @@ class LLCallAfterInventoryBatchMgr: public LLEventTimer
 		LLEventTimer(5.0)
 	{
 		if (!mTrackingPhase.empty())
-		{
+	{
 			selfStartPhase(mTrackingPhase);
 		}
 	}
@@ -212,23 +212,23 @@ class LLCallAfterInventoryBatchMgr: public LLEventTimer
 			addItem(item->getUUID());
 		}
 	}
-
+		
 	// Request or re-request operation for specified item.
 	void addItem(const LLUUID& item_id)
 	{
 		LL_DEBUGS("Avatar") << "item_id " << item_id << llendl;
-		
+
 		if (!requestOperation(item_id))
 		{
 			LL_DEBUGS("Avatar") << "item_id " << item_id << " requestOperation false, skipping" << llendl;
 			return;
-		}
+	}
 
 		mPendingRequests++;
 		// On a re-request, this will reset the timer.
 		mWaitTimes[item_id] = LLTimer();
 		if (mRetryCounts.find(item_id) == mRetryCounts.end())
-		{
+	{
 			mRetryCounts[item_id] = 0;
 		}
 		else
@@ -242,7 +242,7 @@ class LLCallAfterInventoryBatchMgr: public LLEventTimer
 	void onOp(const LLUUID& src_id, const LLUUID& dst_id, LLTimer timestamp)
 	{
 		if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateLateOpRate"))
-		{
+	{
 			llwarns << "Simulating late operation by punting handling to later" << llendl;
 			doAfterInterval(boost::bind(&LLCallAfterInventoryBatchMgr::onOp,this,src_id,dst_id,timestamp),
 							mRetryAfter);
@@ -265,12 +265,12 @@ class LLCallAfterInventoryBatchMgr: public LLEventTimer
 			onCompletionOrFailure();
 		}
 	}
-
+		
 	void onCompletionOrFailure()
 	{
 		assert (!mCompletionOrFailureCalled);
 		mCompletionOrFailureCalled = true;
-		
+
 		// Will never call onCompletion() if any item has been flagged as
 		// a failure - otherwise could wind up with corrupted
 		// outfit, involuntary nudity, etc.
@@ -288,7 +288,7 @@ class LLCallAfterInventoryBatchMgr: public LLEventTimer
 			onFailure();
 		}
 	}
-
+		
 	void onFailure()
 	{
 		llinfos << "failed" << llendl;
@@ -300,7 +300,7 @@ class LLCallAfterInventoryBatchMgr: public LLEventTimer
 		llinfos << "done" << llendl;
 		mOnCompletionFunc();
 	}
-	
+
 	// virtual
 	// Will be deleted after returning true - only safe to do this if all callbacks have fired.
 	BOOL tick()
@@ -313,7 +313,7 @@ class LLCallAfterInventoryBatchMgr: public LLEventTimer
 		// been serviced, since it will result in this object being
 		// deleted.
 		bool all_done = (mPendingRequests==0);
-
+		
 		if (!mWaitTimes.empty())
 		{
 			llwarns << "still waiting on " << mWaitTimes.size() << " items" << llendl;
@@ -323,20 +323,20 @@ class LLCallAfterInventoryBatchMgr: public LLEventTimer
 				// Use a copy of iterator because it may be erased/invalidated.
 				std::map<LLUUID,LLTimer>::iterator curr_it = it;
 				++it;
-				
+
 				F32 time_waited = curr_it->second.getElapsedTimeF32();
 				S32 retries = mRetryCounts[curr_it->first];
 				if (time_waited > mRetryAfter)
 				{
 					if (retries < mMaxRetries)
-					{
+		{
 						LL_DEBUGS("Avatar") << "Waited " << time_waited <<
 							" for " << curr_it->first << ", retrying" << llendl;
 						mRetryCount++;
 						addItem(curr_it->first);
-					}
-					else
-					{
+		}
+		else
+		{
 						llwarns << "Giving up on " << curr_it->first << " after too many retries" << llendl;
 						mWaitTimes.erase(curr_it);
 						mFailCount++;
@@ -347,8 +347,8 @@ class LLCallAfterInventoryBatchMgr: public LLEventTimer
 					onCompletionOrFailure();
 				}
 
-			}
 		}
+	}
 		return all_done;
 	}
 
@@ -360,7 +360,7 @@ class LLCallAfterInventoryBatchMgr: public LLEventTimer
 		LL_DEBUGS("Avatar") << "Times: n " << mTimeStats.getCount() << " min " << mTimeStats.getMinValue() << " max " << mTimeStats.getMaxValue() << llendl;
 		LL_DEBUGS("Avatar") << "Mean " << mTimeStats.getMean() << " stddev " << mTimeStats.getStdDev() << llendl;
 	}
-	
+
 	virtual ~LLCallAfterInventoryBatchMgr()
 	{
 		LL_DEBUGS("Avatar") << "deleting" << llendl;
@@ -397,9 +397,9 @@ class LLCallAfterInventoryCopyMgr: public LLCallAfterInventoryBatchMgr
 	{
 		addItems(src_items);
 	}
-	
+
 	virtual bool requestOperation(const LLUUID& item_id)
-	{
+		{
 		LLViewerInventoryItem *item = gInventory.getItem(item_id);
 		llassert(item);
 		LL_DEBUGS("Avatar") << "copying item " << item_id << llendl;
@@ -479,9 +479,9 @@ class LLCallAfterInventoryLinkMgr: public LLCallAfterInventoryBatchMgr
 			LLAppearanceMgr::instance().purgeBaseOutfitLink(cof);
 
 			if (catp && catp->getPreferredType() == LLFolderType::FT_OUTFIT)
-			{
+	{
 				if (ll_frand() < gSavedSettings.getF32("InventoryDebugSimulateOpFailureRate"))
-				{
+		{
 					LL_DEBUGS("Avatar") << "simulating failure by not sending request for item " << item_id << llendl;
 					return true;
 				}
@@ -841,69 +841,69 @@ bool LLWearableHoldingPattern::pollFetchCompletion()
 void recovered_item_link_cb(const LLUUID& item_id, LLWearableType::EType type, LLViewerWearable *wearable, LLWearableHoldingPattern* holder)
 {
 	if (!holder->isMostRecent())
-	{
-		llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
-		// runway skip here?
-	}
+		{
+			llwarns << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
+			// runway skip here?
+		}
 
 	llinfos << "Recovered item link for type " << type << llendl;
 	holder->eraseTypeToLink(type);
-	// Add wearable to FoundData for actual wearing
-	LLViewerInventoryItem *item = gInventory.getItem(item_id);
-	LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL;
+		// Add wearable to FoundData for actual wearing
+		LLViewerInventoryItem *item = gInventory.getItem(item_id);
+		LLViewerInventoryItem *linked_item = item ? item->getLinkedItem() : NULL;
 
-	if (linked_item)
-	{
-		gInventory.addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID());
-			
-		if (item)
+		if (linked_item)
 		{
-			LLFoundData found(linked_item->getUUID(),
-							  linked_item->getAssetUUID(),
-							  linked_item->getName(),
-							  linked_item->getType(),
-							  linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID,
-							  true // is replacement
-				);
+			gInventory.addChangedMask(LLInventoryObserver::LABEL, linked_item->getUUID());
+			
+			if (item)
+			{
+				LLFoundData found(linked_item->getUUID(),
+								  linked_item->getAssetUUID(),
+								  linked_item->getName(),
+								  linked_item->getType(),
+								  linked_item->isWearableType() ? linked_item->getWearableType() : LLWearableType::WT_INVALID,
+								  true // is replacement
+					);
 			found.mWearable = wearable;
 			holder->getFoundList().push_front(found);
+			}
+			else
+			{
+				llwarns << self_av_string() << "inventory item not found for recovered wearable" << llendl;
+			}
 		}
 		else
 		{
-			llwarns << self_av_string() << "inventory item not found for recovered wearable" << llendl;
+			llwarns << self_av_string() << "inventory link not found for recovered wearable" << llendl;
 		}
 	}
-	else
-	{
-		llwarns << self_av_string() << "inventory link not found for recovered wearable" << llendl;
-	}
-}
 
 void recovered_item_cb(const LLUUID& item_id, LLWearableType::EType type, LLViewerWearable *wearable, LLWearableHoldingPattern* holder)
 {
 	if (!holder->isMostRecent())
-	{
-		// runway skip here?
-		llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
-	}
+		{
+			// runway skip here?
+			llwarns << self_av_string() << "skipping because LLWearableHolding pattern is invalid (superceded by later outfit request)" << llendl;
+		}
 
 	LL_DEBUGS("Avatar") << self_av_string() << "Recovered item for type " << type << LL_ENDL;
-	LLViewerInventoryItem *itemp = gInventory.getItem(item_id);
+		LLViewerInventoryItem *itemp = gInventory.getItem(item_id);
 	wearable->setItemID(item_id);
 	LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(recovered_item_link_cb,_1,type,wearable,holder));
 	holder->eraseTypeToRecover(type);
-	llassert(itemp);
-	if (itemp)
-	{
-		link_inventory_item( gAgent.getID(),
-							 item_id,
-							 LLAppearanceMgr::instance().getCOF(),
-							 itemp->getName(),
-							 itemp->getDescription(),
-							 LLAssetType::AT_LINK,
-							 cb);
+		llassert(itemp);
+		if (itemp)
+		{
+			link_inventory_item( gAgent.getID(),
+					     item_id,
+					     LLAppearanceMgr::instance().getCOF(),
+					     itemp->getName(),
+						 itemp->getDescription(),
+					     LLAssetType::AT_LINK,
+					     cb);
+		}
 	}
-}
 
 void LLWearableHoldingPattern::recoverMissingWearable(LLWearableType::EType type)
 {
@@ -1290,7 +1290,7 @@ bool LLAppearanceMgr::wearItemOnAvatar(const LLUUID& item_id_to_wear, bool do_up
 	if (gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getLibraryRootFolderID()))
 	{
 		LLPointer<LLInventoryCallback> cb = new LLBoostFuncInventoryCallback(boost::bind(wear_on_avatar_cb,_1,replace));
-		copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(), cb);
+		copy_inventory_item(gAgent.getID(), item_to_wear->getPermissions().getOwner(), item_to_wear->getUUID(), LLUUID::null, std::string(),cb);
 		return false;
 	} 
 	else if (!gInventory.isObjectDescendentOf(item_to_wear->getUUID(), gInventory.getRootFolderID()))
@@ -1680,8 +1680,8 @@ void LLAppearanceMgr::purgeCategory(const LLUUID& category, bool keep_outfit_lin
 			}
 			else
 			{
-				gInventory.purgeObject(item->getUUID());
-			}
+			gInventory.purgeObject(item->getUUID());
+		}
 #else
 			gInventory.purgeObject(item->getUUID());
 		}
@@ -2267,7 +2267,7 @@ void LLAppearanceMgr::wearInventoryCategoryOnAvatar( LLInventoryCategory* catego
 	// Avoid unintentionally overwriting old wearables.  We have to do
 	// this up front to avoid having to deal with the case of multiple
 	// wearables being dirty.
-	if (!category) return;
+	if(!category) return;
 
 	if ( !LLInventoryCallbackManager::is_instantiated() )
 	{
@@ -2388,7 +2388,7 @@ void LLAppearanceMgr::addCOFItemLink(const LLUUID &item_id, bool do_update, LLPo
 }
 
 void modified_cof_cb(const LLUUID& inv_item)
-{
+{		
 	LLAppearanceMgr::instance().updateAppearanceFromCOF();
 
 	// Start editing the item if previously requested.
@@ -3237,7 +3237,7 @@ void LLAppearanceMgr::requestServerAppearanceUpdate(LLCurl::ResponderPtr respond
 		llwarns << "No cap for UpdateAvatarAppearance." << llendl;
 		return;
 	}
-	
+
 	LLSD body;
 	S32 cof_version = getCOFVersion();
 	if (gSavedSettings.getBOOL("DebugAvatarExperimentalServerAppearanceUpdate"))
@@ -3253,7 +3253,7 @@ void LLAppearanceMgr::requestServerAppearanceUpdate(LLCurl::ResponderPtr respond
 		}
 	}
 	LL_DEBUGS("Avatar") << "request url " << url << " my_cof_version " << cof_version << llendl;
-	
+
 	//LLCurl::ResponderPtr responder_ptr;
 	if (!responder_ptr.get())
 	{
@@ -3347,33 +3347,33 @@ std::string LLAppearanceMgr::getAppearanceServiceURL() const
 }
 
 void show_created_outfit(LLUUID& folder_id, bool show_panel = true)
-{
-	if (!LLApp::isRunning())
 	{
-		llwarns << "called during shutdown, skipping" << llendl;
-		return;
-	}
-	
-	LLSD key;
-	
+		if (!LLApp::isRunning())
+		{
+			llwarns << "called during shutdown, skipping" << llendl;
+			return;
+		}
+
+		LLSD key;
+		
 	//EXT-7727. For new accounts inventory callback is created during login process
 	// and may be processed after login process is finished
 	if (show_panel)
-	{
-		LLFloaterSidePanelContainer::showPanel("appearance", "panel_outfits_inventory", key);
-		
-	}
-	LLOutfitsList *outfits_list =
-		dynamic_cast<LLOutfitsList*>(LLFloaterSidePanelContainer::getPanel("appearance", "outfitslist_tab"));
-	if (outfits_list)
-	{
+		{
+			LLFloaterSidePanelContainer::showPanel("appearance", "panel_outfits_inventory", key);
+
+		}
+		LLOutfitsList *outfits_list =
+			dynamic_cast<LLOutfitsList*>(LLFloaterSidePanelContainer::getPanel("appearance", "outfitslist_tab"));
+		if (outfits_list)
+		{
 		outfits_list->setSelectedOutfitByUUID(folder_id);
+		}
+
+		LLAppearanceMgr::getInstance()->updateIsDirty();
+		gAgentWearables.notifyLoadingFinished(); // New outfit is saved.
+		LLAppearanceMgr::getInstance()->updatePanelOutfitName("");
 	}
-	
-	LLAppearanceMgr::getInstance()->updateIsDirty();
-	gAgentWearables.notifyLoadingFinished(); // New outfit is saved.
-	LLAppearanceMgr::getInstance()->updatePanelOutfitName("");
-}
 
 LLUUID LLAppearanceMgr::makeNewOutfitLinks(const std::string& new_folder_name, bool show_panel)
 {
@@ -3415,13 +3415,13 @@ void LLAppearanceMgr::removeItemsFromAvatar(const uuid_vec_t& ids_to_remove)
 		llwarns << "called with empty list, nothing to do" << llendl;
 	}
 	for (uuid_vec_t::const_iterator it = ids_to_remove.begin(); it != ids_to_remove.end(); ++it)
-	{
+			{
 		const LLUUID& id_to_remove = *it;
 		const LLUUID& linked_item_id = gInventory.getLinkedItemID(id_to_remove);
 		removeCOFItemLinks(linked_item_id);
-	}
+			}
 	updateAppearanceFromCOF();
-}
+	}
 
 void LLAppearanceMgr::removeItemFromAvatar(const LLUUID& id_to_remove)
 {
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index fdc2cdb78db80943f97d916cc37af8e94fcdee66..f92274dbbd84d0ed7b80bab78b745b4355ef61ac 100755
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -127,9 +127,9 @@
 
 
 #if LL_WINDOWS
-#	include <share.h> // For _SH_DENYWR in initMarkerFile
+#	include <share.h> // For _SH_DENYWR in processMarkerFiles
 #else
-#   include <sys/file.h> // For initMarkerFile support
+#   include <sys/file.h> // For processMarkerFiles
 #endif
 
 #include "llapr.h"
@@ -599,7 +599,8 @@ static void settings_to_globals()
 static void settings_modify()
 {
 	LLRenderTarget::sUseFBO				= gSavedSettings.getBOOL("RenderDeferred");
-	LLPipeline::sRenderDeferred			= gSavedSettings.getBOOL("RenderDeferred");
+	LLPipeline::sRenderBump				= gSavedSettings.getBOOL("RenderObjectBump");
+	LLPipeline::sRenderDeferred		= LLPipeline::sRenderBump && gSavedSettings.getBOOL("RenderDeferred");
 	LLVOAvatar::sUseImpostors			= gSavedSettings.getBOOL("RenderUseImpostors");
 	LLVOSurfacePatch::sLODFactor		= gSavedSettings.getF32("RenderTerrainLODFactor");
 	LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //square lod factor to get exponential range of [1,4]
@@ -741,8 +742,10 @@ bool LLAppViewer::init()
 	// this allows simple skinned file lookups to work
 	gDirUtilp->setSkinFolder("default", "en");
 
-	initLogging();
+	initLoggingAndGetLastDuration();
 	
+	processMarkerFiles();
+
 	//
 	// OK to write stuff to logs now, we've now crash reported if necessary
 	//
@@ -765,7 +768,7 @@ bool LLAppViewer::init()
 	logdir += gDirUtilp->getDirDelimiter();
 	setMiniDumpDir(logdir);
 
-	// Although initLogging() is the right place to mess with
+	// Although initLoggingAndGetLastDuration() is the right place to mess with
 	// setFatalFunction(), we can't query gSavedSettings until after
 	// initConfiguration().
 	S32 rc(gSavedSettings.getS32("QAModeTermCode"));
@@ -1726,7 +1729,7 @@ bool LLAppViewer::cleanup()
 		gAudiop->setStreamingAudioImpl(NULL);
 
 		// shut down the audio subsystem
-        gAudiop->shutdown();
+			gAudiop->shutdown();
 
 		delete gAudiop;
 		gAudiop = NULL;
@@ -1802,6 +1805,8 @@ bool LLAppViewer::cleanup()
 
 	LLAvatarAppearance::cleanupClass();
 	
+	LLAvatarAppearance::cleanupClass();
+	
 	LLPostProcess::cleanupClass();
 
 	LLTracker::cleanupInstance();
@@ -2125,7 +2130,7 @@ void errorCallback(const std::string &error_string)
 	LLError::crashAndLoop(error_string);
 }
 
-void LLAppViewer::initLogging()
+void LLAppViewer::initLoggingAndGetLastDuration()
 {
 	//
 	// Set up logging defaults for the viewer
@@ -2150,24 +2155,35 @@ void LLAppViewer::initLogging()
 	std::string start_marker_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, START_MARKER_FILE_NAME);
 	llstat start_marker_stat;
 	llstat log_file_stat;
-	if (   0 == LLFile::stat(start_marker_file_name, &start_marker_stat)
-		&& 0 == LLFile::stat(log_file, &log_file_stat)
-		)
+	std::ostringstream duration_log_stream; // can't log yet, so save any message for when we can below
+	int start_stat_result = LLFile::stat(start_marker_file_name, &start_marker_stat);
+	int log_stat_result = LLFile::stat(log_file, &log_file_stat);
+	if ( 0 == start_stat_result && 0 == log_stat_result )
 	{
 		int elapsed_seconds = log_file_stat.st_ctime - start_marker_stat.st_ctime;
 		// only report a last run time if the last viewer was the same version
 		// because this stat will be counted against this version
-		gLastExecDuration = markerIsSameVersion(start_marker_file_name) ? elapsed_seconds : -1;
+		if ( markerIsSameVersion(start_marker_file_name) )
+		{
+			gLastExecDuration = elapsed_seconds;
+		}
+		else
+		{
+			duration_log_stream << "start marker from some other version; duration is not reported";
+			gLastExecDuration = -1;
+		}
 	}
 	else
 	{
 		// at least one of the LLFile::stat calls failed, so we can't compute the run time
+		duration_log_stream << "duration stat failure; start: "<< start_stat_result << " log: " << log_stat_result;
 		gLastExecDuration = -1; // unknown
 	}
+	std::string duration_log_msg(duration_log_stream.str());
 	
 	// Create a new start marker file for comparison with log file time for the next run
 	LLAPRFile start_marker_file ;
-	start_marker_file.open(start_marker_file_name, LL_APR_W);
+	start_marker_file.open(start_marker_file_name, LL_APR_WB);
 	if (start_marker_file.getFileHandle())
 	{
 		recordMarkerVersion(start_marker_file);
@@ -2179,6 +2195,10 @@ void LLAppViewer::initLogging()
 
 	// Set the log file to SecondLife.log
 	LLError::logToFile(log_file);
+	if (!duration_log_msg.empty())
+	{
+		LL_WARNS("MarkerFile") << duration_log_msg << LL_ENDL;
+	}
 }
 
 bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key,
@@ -2756,7 +2776,6 @@ bool LLAppViewer::initConfiguration()
 	//
 	// Check for another instance of the app running
 	//
-	mSecondInstance = anotherInstanceRunning();
 	if (mSecondInstance && !gSavedSettings.getBOOL("AllowMultipleViewers"))
 	{
 		std::ostringstream msg;
@@ -2768,8 +2787,6 @@ bool LLAppViewer::initConfiguration()
 		return false;
 	}
 
-	initMarkerFile();
-        
 	if (mSecondInstance)
 	{
 		// This is the second instance of SL. Turn off voice support,
@@ -2970,26 +2987,26 @@ namespace {
 		{
 			LL_WARNS("UpdaterService") << "no info url supplied - defaulting to hard coded release notes pattern" << LL_ENDL;
 
-			// truncate version at the rightmost '.' 
-			std::string version_short(data["version"]);
-			size_t short_length = version_short.rfind('.');
-			if (short_length != std::string::npos)
-			{
-				version_short.resize(short_length);
-			}
+		// truncate version at the rightmost '.' 
+		std::string version_short(data["version"]);
+		size_t short_length = version_short.rfind('.');
+		if (short_length != std::string::npos)
+		{
+			version_short.resize(short_length);
+		}
 
-			LLUIString relnotes_url("[RELEASE_NOTES_BASE_URL][CHANNEL_URL]/[VERSION_SHORT]");
-			relnotes_url.setArg("[VERSION_SHORT]", version_short);
+		LLUIString relnotes_url("[RELEASE_NOTES_BASE_URL][CHANNEL_URL]/[VERSION_SHORT]");
+		relnotes_url.setArg("[VERSION_SHORT]", version_short);
 
-			// *TODO thread the update service's response through to this point
-			std::string const & channel = LLVersionInfo::getChannel();
-			boost::shared_ptr<char> channel_escaped(curl_escape(channel.c_str(), channel.size()), &curl_free);
+		// *TODO thread the update service's response through to this point
+		std::string const & channel = LLVersionInfo::getChannel();
+		boost::shared_ptr<char> channel_escaped(curl_escape(channel.c_str(), channel.size()), &curl_free);
 
-			relnotes_url.setArg("[CHANNEL_URL]", channel_escaped.get());
-			relnotes_url.setArg("[RELEASE_NOTES_BASE_URL]", LLTrans::getString("RELEASE_NOTES_BASE_URL"));
+		relnotes_url.setArg("[CHANNEL_URL]", channel_escaped.get());
+		relnotes_url.setArg("[RELEASE_NOTES_BASE_URL]", LLTrans::getString("RELEASE_NOTES_BASE_URL"));
 			substitutions["INFO_URL"] = relnotes_url.getString();
 		}
-		
+
 		LLNotificationsUtil::add(notification_name, substitutions, LLSD(), apply_callback);
 	}
 
@@ -3455,21 +3472,21 @@ void LLAppViewer::handleViewerCrash()
 	//we're already in a crash situation	
 	if (gDirUtilp)
 	{
-		std::string crash_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
-																	 gLLErrorActivated
-																	 ? LLERROR_MARKER_FILE_NAME
-																	 : ERROR_MARKER_FILE_NAME);
-		LLAPRFile crash_file ;
-		crash_file.open(crash_file_name, LL_APR_W);
-		if (crash_file.getFileHandle())
+		std::string crash_marker_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
+																			gLLErrorActivated
+																			? LLERROR_MARKER_FILE_NAME
+																			: ERROR_MARKER_FILE_NAME);
+		LLAPRFile crash_marker_file ;
+		crash_marker_file.open(crash_marker_file_name, LL_APR_WB);
+		if (crash_marker_file.getFileHandle())
 		{
-			LL_INFOS("MarkerFile") << "Created crash marker file " << crash_file_name << LL_ENDL;
-			recordMarkerVersion(crash_file);
+			LL_INFOS("MarkerFile") << "Created crash marker file " << crash_marker_file_name << LL_ENDL;
+			recordMarkerVersion(crash_marker_file);
 		}
 		else
 		{
-			LL_WARNS("MarkerFile") << "Cannot create error marker file " << crash_file_name << LL_ENDL;
-		}		
+			LL_WARNS("MarkerFile") << "Cannot create error marker file " << crash_marker_file_name << LL_ENDL;
+		}
 	}
 	else
 	{
@@ -3520,38 +3537,6 @@ void LLAppViewer::handleViewerCrash()
 	return;
 }
 
-bool LLAppViewer::anotherInstanceRunning()
-{
-	// We create a marker file when the program starts and remove the file when it finishes.
-	// If the file is currently locked, that means another process is already running.
-
-	std::string marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, MARKER_FILE_NAME);
-	LL_DEBUGS("MarkerFile") << "Checking marker file '"<< marker_file << "' for lock..." << LL_ENDL;
-
-	//Freeze case checks
-	if (LLAPRFile::isExist(marker_file, NULL, LL_APR_RB))
-	{
-		// File exists, try opening with write permissions
-		LLAPRFile outfile ;
-		outfile.open(marker_file, LL_APR_AB);
-		apr_file_t* fMarker = outfile.getFileHandle() ; 
-		if (!fMarker)
-		{
-			// Another instance is running. Skip the rest of these operations.
-			LL_INFOS("MarkerFile") << "Marker file is locked." << LL_ENDL;
-			return true;
-		}
-		if (apr_file_lock(fMarker, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) //flock(fileno(fMarker), LOCK_EX | LOCK_NB) == -1)
-		{
-			LL_INFOS("MarkerFile") << "Marker file is locked." << LL_ENDL;
-			return true;
-		}
-		// No other instances; we'll lock this file now & delete on quit.		
-	}
-	LL_DEBUGS("MarkerFile") << "Marker file isn't locked." << LL_ENDL;
-	return false;
-}
-
 // static
 void LLAppViewer::recordMarkerVersion(LLAPRFile& marker_file) 
 {		
@@ -3596,14 +3581,8 @@ bool LLAppViewer::markerIsSameVersion(const std::string& marker_name) const
 	return sameVersion;
 }
 
-void LLAppViewer::initMarkerFile()
+void LLAppViewer::processMarkerFiles()
 {
-	//First, check for the existence of other files.
-	//There are marker files for two different types of crashes
-	
-	mMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,MARKER_FILE_NAME);
-	LL_DEBUGS("MarkerFile") << "Checking marker file for lock..." << LL_ENDL;
-
 	//We've got 4 things to test for here
 	// - Other Process Running (SecondLife.exec_marker present, locked)
 	// - Freeze (SecondLife.exec_marker present, not locked)
@@ -3611,29 +3590,92 @@ void LLAppViewer::initMarkerFile()
 	// - Other Crash (SecondLife.error_marker present)
 	// These checks should also remove these files for the last 2 cases if they currently exist
 
-	//LLError/Error checks. Only one of these should ever happen at a time.
-	std::string logout_marker_file =  gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOGOUT_MARKER_FILE_NAME);
-	std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME);
-	std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME);
-
-	if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB) && !anotherInstanceRunning())
+	bool marker_is_same_version = true;
+	// first, look for the marker created at startup and deleted on a clean exit
+	mMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,MARKER_FILE_NAME);
+	if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB))
 	{
-		if ( markerIsSameVersion(mMarkerFileName) )
+		// File exists...
+		// first, read it to see if it was created by the same version (we need this later)
+		marker_is_same_version = markerIsSameVersion(mMarkerFileName);
+
+		// now test to see if this file is locked by a running process (try to open for write)
+		LL_DEBUGS("MarkerFile") << "Checking exec marker file for lock..." << LL_ENDL;
+		mMarkerFile.open(mMarkerFileName, LL_APR_WB);
+		apr_file_t* fMarker = mMarkerFile.getFileHandle() ; 
+		if (!fMarker)
+		{
+			LL_INFOS("MarkerFile") << "Exec marker file open failed - assume it is locked." << LL_ENDL;
+			mSecondInstance = true; // lock means that instance is running.
+		}
+		else
 		{
-			LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found" << LL_ENDL;
+			// We were able to open it, now try to lock it ourselves...
+			if (apr_file_lock(fMarker, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS)
+			{
+				LL_WARNS_ONCE("MarkerFile") << "Locking exec marker failed." << LL_ENDL;
+				mSecondInstance = true; // lost a race? be conservative
+			}
+			else
+			{
+				// No other instances; we've locked this file now, so record our version; delete on quit.		
+				recordMarkerVersion(mMarkerFile);
+				LL_DEBUGS("MarkerFile") << "Exec marker file existed but was not locked; rewritten." << LL_ENDL;
+			}
+		}
+
+		if (mSecondInstance)
+		{
+			LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' owned by another instance" << LL_ENDL;
+		}
+		else if (marker_is_same_version)
+		{
+			// the file existed, is ours, and matched our version, so we can report on what it says
+			LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found; last exec FROZE" << LL_ENDL;
 			gLastExecEvent = LAST_EXEC_FROZE;
+				
 		}
 		else
 		{
 			LL_INFOS("MarkerFile") << "Exec marker '"<< mMarkerFileName << "' found, but versions did not match" << LL_ENDL;
 		}
-	}    
+	}
+	else // marker did not exist... last exec (if any) did not freeze
+	{
+		// Create the marker file for this execution & lock it; it will be deleted on a clean exit
+		apr_status_t s;
+		s = mMarkerFile.open(mMarkerFileName, LL_APR_WB, TRUE);	
+
+		if (s == APR_SUCCESS && mMarkerFile.getFileHandle())
+		{
+			LL_DEBUGS("MarkerFile") << "Exec marker file '"<< mMarkerFileName << "' created." << LL_ENDL;
+			if (APR_SUCCESS == apr_file_lock(mMarkerFile.getFileHandle(), APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE)) 
+			{
+				recordMarkerVersion(mMarkerFile);
+				LL_DEBUGS("MarkerFile") << "Exec marker file locked." << LL_ENDL;
+			}
+			else
+			{
+				LL_WARNS("MarkerFile") << "Exec marker file cannot be locked." << LL_ENDL;
+			}
+		}
+		else
+		{
+			LL_WARNS("MarkerFile") << "Failed to create exec marker file '"<< mMarkerFileName << "'." << LL_ENDL;
+		}
+	}
+
+	// now check for cases in which the exec marker may have been cleaned up by crash handlers
+
+	// check for any last exec event report based on whether or not it happened during logout
+	// (the logout marker is created when logout begins)
+	std::string logout_marker_file =  gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOGOUT_MARKER_FILE_NAME);
 	if(LLAPRFile::isExist(logout_marker_file, NULL, LL_APR_RB))
 	{
 		if (markerIsSameVersion(logout_marker_file))
 		{
 			gLastExecEvent = LAST_EXEC_LOGOUT_FROZE;
-			LL_INFOS("MarkerFile") << "Logout crashed '"<< logout_marker_file << "', setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
+			LL_INFOS("MarkerFile") << "Logout crash marker '"<< logout_marker_file << "', changing LastExecEvent to LOGOUT_FROZE" << LL_ENDL;
 		}
 		else
 		{
@@ -3641,89 +3683,86 @@ void LLAppViewer::initMarkerFile()
 		}
 		LLAPRFile::remove(logout_marker_file);
 	}
+	// further refine based on whether or not a marker created during an llerr crash is found
+	std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME);
 	if(LLAPRFile::isExist(llerror_marker_file, NULL, LL_APR_RB))
 	{
 		if (markerIsSameVersion(llerror_marker_file))
 		{
-			gLastExecEvent = ( gLastExecEvent == LAST_EXEC_LOGOUT_FROZE )
-				? LAST_EXEC_LOGOUT_CRASH : LAST_EXEC_LLERROR_CRASH;
-			LL_INFOS("MarkerFile") << "Last exec LLError '"<< llerror_marker_file << "' crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
+			if ( gLastExecEvent == LAST_EXEC_LOGOUT_FROZE )
+			{
+				gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
+				LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL;
+			}
+			else
+			{
+				gLastExecEvent = LAST_EXEC_LLERROR_CRASH;
+				LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' crashed, setting LastExecEvent to LLERROR_CRASH" << LL_ENDL;
+			}
 		}
 		else
 		{
-			LL_INFOS("MarkerFile") << "Last exec LLError marker '"<< llerror_marker_file << "' found, but versions did not match" << LL_ENDL;
+			LL_INFOS("MarkerFile") << "LLError marker '"<< llerror_marker_file << "' found, but versions did not match" << LL_ENDL;
 		}
 		LLAPRFile::remove(llerror_marker_file);
 	}
+	// and last refine based on whether or not a marker created during a non-llerr crash is found
+	std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME);
 	if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB))
 	{
 		if (markerIsSameVersion(error_marker_file))
 		{
-			gLastExecEvent = (gLastExecEvent == LAST_EXEC_LOGOUT_FROZE)
-				? LAST_EXEC_LOGOUT_CRASH : LAST_EXEC_OTHER_CRASH;
-			LL_INFOS("MarkerFile") << "Last exec '"<< error_marker_file << "' crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
+			if (gLastExecEvent == LAST_EXEC_LOGOUT_FROZE)
+			{
+				gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
+				LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to LOGOUT_CRASH" << LL_ENDL;
+			}
+			else
+			{
+				gLastExecEvent = LAST_EXEC_OTHER_CRASH;
+				LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
+			}
 		}
 		else
 		{
-			LL_INFOS("MarkerFile") << "Last exec '"<< error_marker_file << "' marker found, but versions did not match" << LL_ENDL;
+			LL_INFOS("MarkerFile") << "Error marker '"<< error_marker_file << "' marker found, but versions did not match" << LL_ENDL;
 		}
 		LLAPRFile::remove(error_marker_file);
 	}
-
-	// No new markers if another instance is running.
-	if(anotherInstanceRunning()) 
-	{
-		return;
-	}
-	
-	// Create the marker file for this execution & lock it
-	apr_status_t s;
-	s = mMarkerFile.open(mMarkerFileName, LL_APR_W, TRUE);	
-
-	if (s == APR_SUCCESS && mMarkerFile.getFileHandle())
-	{
-		LL_DEBUGS("MarkerFile") << "Marker file '"<< mMarkerFileName << "' created." << LL_ENDL;
-		if (APR_SUCCESS == apr_file_lock(mMarkerFile.getFileHandle(), APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE)) 
-		{
-			recordMarkerVersion(mMarkerFile);
-			LL_DEBUGS("MarkerFile") << "Marker file locked." << LL_ENDL;
-		}
-		else
-		{
-			LL_INFOS("MarkerFile") << "Marker file cannot be locked." << LL_ENDL;
-		}
-	}
-	else
-	{
-		LL_INFOS("MarkerFile") << "Failed to create marker file '"<< mMarkerFileName << "'." << LL_ENDL;
-	}
 }
 
 void LLAppViewer::removeMarkerFile(bool leave_logout_marker)
 {
-	LL_DEBUGS("MarkerFile") << "removeMarkerFile("<<(leave_logout_marker?"leave":"remove") <<" logout)" << LL_ENDL;
-	if (mMarkerFile.getFileHandle())
-	{
-		LL_DEBUGS("MarkerFile") << "removeMarkerFile marker '"<<mMarkerFileName<<"'"<< LL_ENDL;
-		mMarkerFile.close();
-		LLAPRFile::remove( mMarkerFileName );
-	}
-	else
-	{
-		LL_WARNS("MarkerFile") << "removeMarkerFile marker '"<<mMarkerFileName<<"' not open"<< LL_ENDL;
-	}
-	if (!leave_logout_marker)
-	{
-		if (mLogoutMarkerFile.getFileHandle())
+	if (!mSecondInstance)
+	{		
+		LL_DEBUGS("MarkerFile") << (leave_logout_marker?"leave":"remove") <<" logout" << LL_ENDL;
+		if (mMarkerFile.getFileHandle())
 		{
-			LL_DEBUGS("MarkerFile") << "removeMarkerFile logout marker '"<<mLogoutMarkerFileName<<"'"<< LL_ENDL;
-			mLogoutMarkerFile.close();
+			LL_DEBUGS("MarkerFile") << "removing exec marker '"<<mMarkerFileName<<"'"<< LL_ENDL;
+			mMarkerFile.close() ;
+			LLAPRFile::remove( mMarkerFileName );
 		}
 		else
 		{
-			LL_WARNS("MarkerFile") << "removeMarkerFile logout marker '"<<mLogoutMarkerFileName<<"' not open"<< LL_ENDL;
+			LL_WARNS("MarkerFile") << "marker '"<<mMarkerFileName<<"' not open"<< LL_ENDL;
 		}
-		LLAPRFile::remove( mLogoutMarkerFileName );
+		if (!leave_logout_marker)
+		{
+			if (mLogoutMarkerFile.getFileHandle())
+			{
+				LL_DEBUGS("MarkerFile") << "removing logout marker '"<<mLogoutMarkerFileName<<"'"<< LL_ENDL;
+				mLogoutMarkerFile.close();
+			}
+			else
+			{
+				LL_WARNS("MarkerFile") << "logout marker '"<<mLogoutMarkerFileName<<"' not open"<< LL_ENDL;
+			}
+			LLAPRFile::remove( mLogoutMarkerFileName );
+		}
+	}
+	else
+	{
+		LL_WARNS("MarkerFile") << "leaving markers because this is a second instance" << LL_ENDL;
 	}
 }
 
@@ -3778,6 +3817,12 @@ void LLAppViewer::requestQuit()
 		gAgentAvatarp->updateAvatarRezMetrics(true); // force a last packet to be sent.
 	}
 	
+	// Try to send last batch of avatar rez metrics.
+	if (!gDisconnected && isAgentAvatarValid())
+	{
+		gAgentAvatarp->updateAvatarRezMetrics(true); // force a last packet to be sent.
+	}
+	
 	LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
 	effectp->setPositionGlobal(gAgent.getPositionGlobal());
 	effectp->setColor(LLColor4U(gAgent.getEffectColor()));
@@ -4916,6 +4961,22 @@ void LLAppViewer::sendLogoutRequest()
 {
 	if(!mLogoutRequestSent && gMessageSystem)
 	{
+		//Set internal status variables and marker files before actually starting the logout process
+		gLogoutInProgress = TRUE;
+		mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LOGOUT_MARKER_FILE_NAME);
+		
+		LLAPRFile outfile ;
+		mLogoutMarkerFile.open(mLogoutMarkerFileName, LL_APR_WB);
+		if (mLogoutMarkerFile.getFileHandle())
+		{
+			LL_INFOS("MarkerFile") << "Created logout marker file '"<< mLogoutMarkerFileName << "' " << LL_ENDL;
+			recordMarkerVersion(outfile);
+		}
+		else
+		{
+			LL_WARNS("MarkerFile") << "Cannot create logout marker file " << mLogoutMarkerFileName << LL_ENDL;
+		}		
+
 		LLMessageSystem* msg = gMessageSystem;
 		msg->newMessageFast(_PREHASH_LogoutRequest);
 		msg->nextBlockFast(_PREHASH_AgentData);
@@ -4931,22 +4992,6 @@ void LLAppViewer::sendLogoutRequest()
 		{
 			LLVoiceClient::getInstance()->leaveChannel();
 		}
-
-		//Set internal status variables and marker files
-		gLogoutInProgress = TRUE;
-		mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LOGOUT_MARKER_FILE_NAME);
-		
-		LLAPRFile outfile ;
-		mLogoutMarkerFile.open(mLogoutMarkerFileName, LL_APR_W);
-		if (mLogoutMarkerFile.getFileHandle())
-		{
-			LL_INFOS("MarkerFile") << "Created logout marker file '"<< mLogoutMarkerFileName << "' " << mLogoutMarkerFileName << LL_ENDL;
-			recordMarkerVersion(outfile);
-		}
-		else
-		{
-			LL_WARNS("MarkerFile") << "Cannot create logout marker file " << mLogoutMarkerFileName << LL_ENDL;
-		}		
 	}
 }
 
@@ -5195,11 +5240,12 @@ void LLAppViewer::disconnectViewer()
 
 void LLAppViewer::forceErrorLLError()
 {
-   	llerrs << "This is an llerror" << llendl;
+   	llerrs << "This is a deliberate llerror" << llendl;
 }
 
 void LLAppViewer::forceErrorBreakpoint()
 {
+   	llwarns << "Forcing a deliberate breakpoint" << llendl;
 #ifdef LL_WINDOWS
     DebugBreak();
 #endif
@@ -5208,6 +5254,7 @@ void LLAppViewer::forceErrorBreakpoint()
 
 void LLAppViewer::forceErrorBadMemoryAccess()
 {
+   	llwarns << "Forcing a deliberate bad memory access" << llendl;
     S32* crash = NULL;
     *crash = 0xDEADBEEF;  
     return;
@@ -5215,6 +5262,7 @@ void LLAppViewer::forceErrorBadMemoryAccess()
 
 void LLAppViewer::forceErrorInfiniteLoop()
 {
+   	llwarns << "Forcing a deliberate infinite loop" << llendl;
     while(true)
     {
         ;
@@ -5224,12 +5272,14 @@ void LLAppViewer::forceErrorInfiniteLoop()
  
 void LLAppViewer::forceErrorSoftwareException()
 {
+   	llwarns << "Forcing a deliberate exception" << llendl;
     // *FIX: Any way to insure it won't be handled?
     throw; 
 }
 
 void LLAppViewer::forceErrorDriverCrash()
 {
+   	llwarns << "Forcing a deliberate driver crash" << llendl;
 	glDeleteTextures(1, NULL);
 }
 
@@ -5342,7 +5392,7 @@ void LLAppViewer::handleLoginComplete()
 
 void LLAppViewer::launchUpdater()
 {
-	LLSD query_map = LLSD::emptyMap();
+		LLSD query_map = LLSD::emptyMap();
 	query_map["os"] = gPlatform;
 
 	// *TODO change userserver to be grid on both viewer and sim, since
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index d3a8cf24d9a13aef2b8b0372dd69361c73fd0745..cd91ae8b2bc9c3ba76b67418270af5c6d939790d 100755
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -183,7 +183,7 @@ class LLAppViewer : public LLApp
 	
 protected:
 	virtual bool initWindow(); // Initialize the viewer's window.
-	virtual void initLogging(); // Initialize log files, logging system
+	virtual void initLoggingAndGetLastDuration(); // Initialize log files, logging system
 	virtual void initConsole() {}; // Initialize OS level debugging console.
 	virtual bool initHardwareTest() { return true; } // A false result indicates the app should quit.
 	virtual bool initSLURLHandler();
@@ -215,8 +215,7 @@ class LLAppViewer : public LLApp
 
 	void writeSystemInfo(); // Write system info to "debug_info.log"
 
-	bool anotherInstanceRunning(); 
-	void initMarkerFile(); 
+	void processMarkerFiles(); 
 	static void recordMarkerVersion(LLAPRFile& marker_file);
 	bool markerIsSameVersion(const std::string& marker_name) const;
 	
diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp
index 5f98fd0a34f58a149129906e351dd173a1635563..b16bb573e1b483ffd6958312bd16581397effb7f 100755
--- a/indra/newview/llappviewerlinux.cpp
+++ b/indra/newview/llappviewerlinux.cpp
@@ -440,7 +440,7 @@ bool LLAppViewerLinux::beingDebugged()
 #endif
 }
 
-void LLAppViewerLinux::initLogging()
+void LLAppViewerLinux::initLoggingAndGetLastDuration()
 {
 	// Remove the last stack trace, if any
 	// This file is no longer created, since the move to Google Breakpad
@@ -449,7 +449,7 @@ void LLAppViewerLinux::initLogging()
 		gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"stack_trace.log");
 	LLFile::remove(old_stack_file);
 
-	LLAppViewer::initLogging();
+	LLAppViewer::initLoggingAndGetLastDuration();
 }
 
 bool LLAppViewerLinux::initParseCommandLine(LLCommandLineParser& clp)
diff --git a/indra/newview/llappviewerlinux.h b/indra/newview/llappviewerlinux.h
index b30977acb3d5a075c609e5b7981ae172340808b8..fb77600c10e7c02ca2ff45f9f8fa57f0eeba107c 100755
--- a/indra/newview/llappviewerlinux.h
+++ b/indra/newview/llappviewerlinux.h
@@ -63,7 +63,7 @@ class LLAppViewerLinux : public LLAppViewer
 	virtual bool restoreErrorTrap();
 	virtual void handleCrashReporting(bool reportFreeze);
 
-	virtual void initLogging();
+	virtual void initLoggingAndGetLastDuration();
 	virtual bool initParseCommandLine(LLCommandLineParser& clp);
 
 	virtual bool initSLURLHandler();
diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp
index 0ba3669487a903302ef69b8c2e308d5eaf9edc32..3cf3c739d942b27a3205027018ce8526bcae6491 100755
--- a/indra/newview/llappviewerwin32.cpp
+++ b/indra/newview/llappviewerwin32.cpp
@@ -490,7 +490,7 @@ bool LLAppViewerWin32::init()
 	// (Don't send our data to Microsoft--at least until we are Logo approved and have a way
 	// of getting the data back from them.)
 	//
-	llinfos << "Turning off Windows error reporting." << llendl;
+	// llinfos << "Turning off Windows error reporting." << llendl;
 	disableWinErrorReporting();
 
 #ifndef LL_RELEASE_FOR_DOWNLOAD
@@ -509,9 +509,9 @@ bool LLAppViewerWin32::cleanup()
 	return result;
 }
 
-void LLAppViewerWin32::initLogging()
+void LLAppViewerWin32::initLoggingAndGetLastDuration()
 {
-	LLAppViewer::initLogging();
+	LLAppViewer::initLoggingAndGetLastDuration();
 }
 
 void LLAppViewerWin32::initConsole()
diff --git a/indra/newview/llappviewerwin32.h b/indra/newview/llappviewerwin32.h
index d95174dd1d92155589499a2731793d16a3bc8f7c..386bddd495dbd9326de6a4803dcd6811f1330746 100755
--- a/indra/newview/llappviewerwin32.h
+++ b/indra/newview/llappviewerwin32.h
@@ -44,7 +44,7 @@ class LLAppViewerWin32 : public LLAppViewer
 	virtual bool cleanup();
 
 protected:
-	virtual void initLogging(); // Override to clean stack_trace info.
+	virtual void initLoggingAndGetLastDuration(); // Override to clean stack_trace info.
 	virtual void initConsole(); // Initialize OS level debugging console.
 	virtual bool initHardwareTest(); // Win32 uses DX9 to test hardware.
 	virtual bool initParseCommandLine(LLCommandLineParser& clp);
diff --git a/indra/newview/lldrawable.cpp b/indra/newview/lldrawable.cpp
index 47306d3a6a74e93a6da4b0193a6feafa5e3a8c7d..8c9fd4152aa1af6f5edfadb42801c1c7a79fe934 100755
--- a/indra/newview/lldrawable.cpp
+++ b/indra/newview/lldrawable.cpp
@@ -308,6 +308,49 @@ LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep)
 
 }
 
+LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp)
+{
+	LLFace *face;
+	face = new LLFace(this, mVObjp);
+	
+	face->setTEOffset(mFaces.size());
+	face->setTexture(texturep);
+	face->setNormalMap(normalp);
+	face->setPoolType(gPipeline.getPoolTypeFromTE(te, texturep));
+	
+	mFaces.push_back(face);
+	
+	if (isState(UNLIT))
+	{
+		face->setState(LLFace::FULLBRIGHT);
+	}
+	
+	return face;
+	
+}
+
+LLFace*	LLDrawable::addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp, LLViewerTexture *specularp)
+{
+	LLFace *face;
+	face = new LLFace(this, mVObjp);
+	
+	face->setTEOffset(mFaces.size());
+	face->setTexture(texturep);
+	face->setNormalMap(normalp);
+	face->setSpecularMap(specularp);
+	face->setPoolType(gPipeline.getPoolTypeFromTE(te, texturep));
+	
+	mFaces.push_back(face);
+	
+	if (isState(UNLIT))
+	{
+		face->setState(LLFace::FULLBRIGHT);
+	}
+	
+	return face;
+	
+}
+
 void LLDrawable::setNumFaces(const S32 newFaces, LLFacePool *poolp, LLViewerTexture *texturep)
 {
 	if (newFaces == (S32)mFaces.size())
diff --git a/indra/newview/lldrawable.h b/indra/newview/lldrawable.h
index 4420a34fae2d74b60d25ab0e5ee3cdb877222f53..c3f6d77edc3bd9ba31d1b221eb0089ef36c78b67 100755
--- a/indra/newview/lldrawable.h
+++ b/indra/newview/lldrawable.h
@@ -145,6 +145,8 @@ class LLDrawable : public LLRefCount
 	//void                removeFace(const S32 i); // SJB: Avoid using this, it's slow
 	LLFace*				addFace(LLFacePool *poolp, LLViewerTexture *texturep);
 	LLFace*				addFace(const LLTextureEntry *te, LLViewerTexture *texturep);
+	LLFace*				addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp);
+	LLFace*				addFace(const LLTextureEntry *te, LLViewerTexture *texturep, LLViewerTexture *normalp, LLViewerTexture *specularp);
 	void				deleteFaces(S32 offset, S32 count);
 	void                setNumFaces(const S32 numFaces, LLFacePool *poolp, LLViewerTexture *texturep);
 	void                setNumFacesFast(const S32 numFaces, LLFacePool *poolp, LLViewerTexture *texturep);
diff --git a/indra/newview/lldrawpool.cpp b/indra/newview/lldrawpool.cpp
index 94dd927d26ce1a53dcdcdb85def8bf99b2f29ff1..04e31e648678dc5166db54663a4049c1e1b630c9 100755
--- a/indra/newview/lldrawpool.cpp
+++ b/indra/newview/lldrawpool.cpp
@@ -35,6 +35,7 @@
 #include "lldrawpoolalpha.h"
 #include "lldrawpoolavatar.h"
 #include "lldrawpoolbump.h"
+#include "lldrawpoolmaterials.h"
 #include "lldrawpoolground.h"
 #include "lldrawpoolsimple.h"
 #include "lldrawpoolsky.h"
@@ -47,6 +48,7 @@
 #include "llspatialpartition.h"
 #include "llviewercamera.h"
 #include "lldrawpoolwlsky.h"
+#include "llglslshader.h"
 
 S32 LLDrawPool::sNumDrawPools = 0;
 
@@ -64,6 +66,12 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerTexture *tex0)
 	case POOL_GRASS:
 		poolp = new LLDrawPoolGrass();
 		break;
+	case POOL_ALPHA_MASK:
+		poolp = new LLDrawPoolAlphaMask();
+		break;
+	case POOL_FULLBRIGHT_ALPHA_MASK:
+		poolp = new LLDrawPoolFullbrightAlphaMask();
+		break;
 	case POOL_FULLBRIGHT:
 		poolp = new LLDrawPoolFullbright();
 		break;
@@ -98,6 +106,9 @@ LLDrawPool *LLDrawPool::createPool(const U32 type, LLViewerTexture *tex0)
 	case POOL_BUMP:
 		poolp = new LLDrawPoolBump();
 		break;
+	case POOL_MATERIALS:
+		poolp = new LLDrawPoolMaterials();
+		break;
 	case POOL_WL_SKY:
 		poolp = new LLDrawPoolWLSky();
 		break;
@@ -411,6 +422,27 @@ void LLRenderPass::pushBatches(U32 type, U32 mask, BOOL texture, BOOL batch_text
 	}
 }
 
+void LLRenderPass::pushMaskBatches(U32 type, U32 mask, BOOL texture, BOOL batch_textures)
+{
+	for (LLCullResult::drawinfo_iterator i = gPipeline.beginRenderMap(type); i != gPipeline.endRenderMap(type); ++i)	
+	{
+		LLDrawInfo* pparams = *i;
+		if (pparams) 
+		{
+			if (LLGLSLShader::sCurBoundShaderPtr)
+			{
+				LLGLSLShader::sCurBoundShaderPtr->setMinimumAlpha(pparams->mAlphaMaskCutoff);
+			}
+			else
+			{
+				gGL.setAlphaRejectSettings(LLRender::CF_GREATER, pparams->mAlphaMaskCutoff);
+			}
+			
+			pushBatch(*pparams, mask, texture, batch_textures);
+		}
+	}
+}
+
 void LLRenderPass::applyModelMatrix(LLDrawInfo& params)
 {
 	if (params.mModelMatrix != gGLLastMatrix)
diff --git a/indra/newview/lldrawpool.h b/indra/newview/lldrawpool.h
index ab9bb9e611ebbf0becf5091cb03fb0422f08c28d..3bde0d29befc36b26cb460730df24fc195496a6c 100755
--- a/indra/newview/lldrawpool.h
+++ b/indra/newview/lldrawpool.h
@@ -50,10 +50,13 @@ class LLDrawPool
 		POOL_GROUND,
 		POOL_FULLBRIGHT,
 		POOL_BUMP,
+		POOL_MATERIALS,
 		POOL_TERRAIN,	
 		POOL_SKY,
 		POOL_WL_SKY,
 		POOL_TREE,
+		POOL_ALPHA_MASK,
+		POOL_FULLBRIGHT_ALPHA_MASK,
 		POOL_GRASS,
 		POOL_INVISIBLE, // see below *
 		POOL_AVATAR,
@@ -133,6 +136,22 @@ class LLRenderPass : public LLDrawPool
 		PASS_SHINY,
 		PASS_BUMP,
 		PASS_POST_BUMP,
+		PASS_MATERIAL,
+		PASS_MATERIAL_ALPHA,
+		PASS_MATERIAL_ALPHA_MASK,
+		PASS_MATERIAL_ALPHA_EMISSIVE,
+		PASS_SPECMAP,
+		PASS_SPECMAP_BLEND,
+		PASS_SPECMAP_MASK,
+		PASS_SPECMAP_EMISSIVE,
+		PASS_NORMMAP,
+		PASS_NORMMAP_BLEND,
+		PASS_NORMMAP_MASK,
+		PASS_NORMMAP_EMISSIVE,
+		PASS_NORMSPEC,
+		PASS_NORMSPEC_BLEND,
+		PASS_NORMSPEC_MASK,
+		PASS_NORMSPEC_EMISSIVE,
 		PASS_GLOW,
 		PASS_ALPHA,
 		PASS_ALPHA_MASK,
@@ -151,6 +170,7 @@ class LLRenderPass : public LLDrawPool
 
 	static void applyModelMatrix(LLDrawInfo& params);
 	virtual void pushBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE);
+	virtual void pushMaskBatches(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_textures = FALSE);
 	virtual void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE);
 	virtual void renderGroup(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
 	virtual void renderGroups(U32 type, U32 mask, BOOL texture = TRUE);
diff --git a/indra/newview/lldrawpoolalpha.cpp b/indra/newview/lldrawpoolalpha.cpp
index 313b310e1e87769b87bedf3de987eee8c60dd53a..c832e1401da8076bd92b2a6b484d6a46427a1384 100755
--- a/indra/newview/lldrawpoolalpha.cpp
+++ b/indra/newview/lldrawpoolalpha.cpp
@@ -71,33 +71,6 @@ void LLDrawPoolAlpha::prerender()
 	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
 }
 
-S32 LLDrawPoolAlpha::getNumDeferredPasses()
-{
-	return 1;
-}
-
-void LLDrawPoolAlpha::beginDeferredPass(S32 pass)
-{
-	
-}
-
-void LLDrawPoolAlpha::endDeferredPass(S32 pass)
-{
-	
-}
-
-void LLDrawPoolAlpha::renderDeferred(S32 pass)
-{
-	LLFastTimer t(FTM_RENDER_GRASS);
-	gDeferredDiffuseAlphaMaskProgram.bind();
-	gDeferredDiffuseAlphaMaskProgram.setMinimumAlpha(0.33f);
-
-	//render alpha masked objects
-	LLRenderPass::pushBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-	gDeferredDiffuseAlphaMaskProgram.unbind();			
-}
-
-
 S32 LLDrawPoolAlpha::getNumPostDeferredPasses() 
 { 
 	if (LLPipeline::sImpostorRender)
@@ -121,8 +94,10 @@ void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass)
 	if (pass == 0)
 	{
 		simple_shader = &gDeferredAlphaProgram;
-		fullbright_shader = &gObjectFullbrightAlphaMaskProgram;
-
+		fullbright_shader = &gObjectFullbrightProgram;
+		fullbright_shader->bind();
+		fullbright_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f); 
+		fullbright_shader->unbind();
 		//prime simple shader (loads shadow relevant uniforms)
 		gPipeline.bindDeferredShader(*simple_shader);
 	}
@@ -133,8 +108,7 @@ void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass)
 		gPipeline.mDeferredDepth.copyContents(gPipeline.mDeferredScreen, 0, 0, gPipeline.mDeferredScreen.getWidth(), gPipeline.mDeferredScreen.getHeight(),
 							0, 0, gPipeline.mDeferredDepth.getWidth(), gPipeline.mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);	
 		gPipeline.mDeferredDepth.bindTarget();
-		simple_shader = NULL;
-		fullbright_shader = NULL;
+		simple_shader = fullbright_shader = &gObjectFullbrightAlphaMaskProgram;
 		gObjectFullbrightAlphaMaskProgram.bind();
 		gObjectFullbrightAlphaMaskProgram.setMinimumAlpha(0.33f);
 	}
@@ -150,7 +124,6 @@ void LLDrawPoolAlpha::beginPostDeferredPass(S32 pass)
 
 void LLDrawPoolAlpha::endPostDeferredPass(S32 pass) 
 { 
-
 	if (pass == 1)
 	{
 		gPipeline.mDeferredDepth.flush();
@@ -173,14 +146,14 @@ void LLDrawPoolAlpha::beginRenderPass(S32 pass)
 	
 	if (LLPipeline::sUnderWaterRender)
 	{
-		simple_shader = &gObjectSimpleWaterAlphaMaskProgram;
-		fullbright_shader = &gObjectFullbrightWaterAlphaMaskProgram;
+		simple_shader = &gObjectSimpleWaterProgram;
+		fullbright_shader = &gObjectFullbrightWaterProgram;
 		emissive_shader = &gObjectEmissiveWaterProgram;
 	}
 	else
 	{
-		simple_shader = &gObjectSimpleAlphaMaskProgram;
-		fullbright_shader = &gObjectFullbrightAlphaMaskProgram;
+		simple_shader = &gObjectSimpleProgram;
+		fullbright_shader = &gObjectFullbrightProgram;
 		emissive_shader = &gObjectEmissiveProgram;
 	}
 
@@ -218,43 +191,7 @@ void LLDrawPoolAlpha::render(S32 pass)
 	{
 		gGL.setColorMask(true, true);
 	}
-
-	if (LLPipeline::sAutoMaskAlphaNonDeferred)
-	{
-		mColorSFactor = LLRender::BF_ONE;  // }
-		mColorDFactor = LLRender::BF_ZERO; // } these are like disabling blend on the color channels, but we're still blending on the alpha channel so that we can suppress glow
-		mAlphaSFactor = LLRender::BF_ZERO;
-		mAlphaDFactor = LLRender::BF_ZERO; // block (zero-out) glow where the alpha test succeeds
-		gGL.blendFunc(mColorSFactor, mColorDFactor, mAlphaSFactor, mAlphaDFactor);
-
-		if (mVertexShaderLevel > 0)
-		{
-			if (!LLPipeline::sRenderDeferred || !deferred_render)
-			{
-				simple_shader->bind();
-				simple_shader->setMinimumAlpha(0.33f);
-
-				pushBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-			}
-			if (fullbright_shader)
-			{
-				fullbright_shader->bind();
-				fullbright_shader->setMinimumAlpha(0.33f);
-			}
-			pushBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
-			//LLGLSLShader::bindNoShader();
-		}
-		else
-		{
-			gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.33f); //OK
-			gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
-			pushBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask());
-			gPipeline.enableLightsDynamic();
-			pushBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask());
-			gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); //OK
-		}
-	}
-
+	
 	LLGLDepthTest depth(GL_TRUE, LLDrawPoolWater::sSkipScreenCopy || 
 				(deferred_render && pass == 1) ? GL_TRUE : GL_FALSE);
 
@@ -302,7 +239,7 @@ void LLDrawPoolAlpha::render(S32 pass)
 
 	if (mVertexShaderLevel > 0)
 	{
-		renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX);
+		renderAlpha(getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2);
 	}
 	else
 	{
@@ -412,8 +349,14 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 				}
 
 				LLRenderPass::applyModelMatrix(params);
-
 				
+				LLMaterial* mat = NULL;
+
+				if (deferred_render && !LLPipeline::sUnderWaterRender)
+				{
+					mat = params.mMaterial;
+				}
+
 				if (params.mFullbright)
 				{
 					// Turn off lighting if it hasn't already been so.
@@ -446,11 +389,30 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 					light_enabled = TRUE;
 				}
 
-				// If we need shaders, and we're not ALREADY using the proper shader, then bind it
-				// (this way we won't rebind shaders unnecessarily).
-				if(use_shaders && (current_shader != target_shader))
+				if (deferred_render && mat)
 				{
-					llassert(target_shader != NULL);
+					U32 mask = params.mShaderMask;
+
+					llassert(mask < LLMaterial::SHADER_COUNT);
+					target_shader = &(gDeferredMaterialProgram[mask]);
+
+					if (current_shader != target_shader)
+					{
+						gPipeline.bindDeferredShader(*target_shader);
+					}
+				}
+				else if (!params.mFullbright)
+				{
+					target_shader = simple_shader;
+				}
+				else
+				{
+					target_shader = fullbright_shader;
+				}
+				
+				if(use_shaders && (current_shader != target_shader))
+				{// If we need shaders, and we're not ALREADY using the proper shader, then bind it
+				// (this way we won't rebind shaders unnecessarily).
 					current_shader = target_shader;
 					current_shader->bind();
 				}
@@ -459,6 +421,38 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 					LLGLSLShader::bindNoShader();
 					current_shader = NULL;
 				}
+				
+				if (use_shaders && mat)
+				{
+					// We have a material.  Supply the appropriate data here.
+					if (LLPipeline::sRenderDeferred)
+					{
+						current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, params.mSpecColor.mV[0], params.mSpecColor.mV[1], params.mSpecColor.mV[2], params.mSpecColor.mV[3]);						
+						current_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, params.mEnvIntensity);
+						current_shader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, params.mFullbright ? 1.f : 0.f);
+
+						if (params.mNormalMap)
+						{
+							params.mNormalMap->addTextureStats(params.mVSize);
+							current_shader->bindTexture(LLShaderMgr::BUMP_MAP, params.mNormalMap);
+						} 
+						
+						if (params.mSpecularMap)
+						{
+							params.mSpecularMap->addTextureStats(params.mVSize);
+							current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, params.mSpecularMap);
+						} 
+					}
+
+				} else if (LLPipeline::sRenderDeferred && current_shader && (current_shader == simple_shader))
+				{
+					current_shader->uniform4f(LLShaderMgr::SPECULAR_COLOR, 1.0f, 1.0f, 1.0f, 1.0f);						
+					current_shader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, 0.0f);			
+					LLViewerFetchedTexture::sFlatNormalImagep->addTextureStats(params.mVSize);
+					current_shader->bindTexture(LLShaderMgr::BUMP_MAP, LLViewerFetchedTexture::sFlatNormalImagep);						
+					LLViewerFetchedTexture::sWhiteImagep->addTextureStats(params.mVSize);
+					current_shader->bindTexture(LLShaderMgr::SPECULAR_MAP, LLViewerFetchedTexture::sWhiteImagep);
+				}
 
 				if (params.mGroup)
 				{
@@ -477,12 +471,20 @@ void LLDrawPoolAlpha::renderAlpha(U32 mask)
 						}
 					}
 				}
-				else
+				else  
 				{ //not batching textures or batch has only 1 texture -- might need a texture matrix
 					if (params.mTexture.notNull())
 					{
 						params.mTexture->addTextureStats(params.mVSize);
-						gGL.getTexUnit(0)->bind(params.mTexture, TRUE) ;
+						if (use_shaders && mat)
+						{
+							current_shader->bindTexture(LLShaderMgr::DIFFUSE_MAP, params.mTexture);
+						}
+						else
+						{
+							gGL.getTexUnit(0)->bind(params.mTexture, TRUE);
+						}
+						
 						if (params.mTextureMatrix)
 						{
 							tex_setup = true;
diff --git a/indra/newview/lldrawpoolalpha.h b/indra/newview/lldrawpoolalpha.h
index a4245e561d85cf3e70a377b59c73405b8f219805..43122218edadba815be0945cf5911beeb18fd27d 100755
--- a/indra/newview/lldrawpoolalpha.h
+++ b/indra/newview/lldrawpoolalpha.h
@@ -50,11 +50,6 @@ class LLDrawPoolAlpha: public LLRenderPass
 	LLDrawPoolAlpha(U32 type = LLDrawPool::POOL_ALPHA);
 	/*virtual*/ ~LLDrawPoolAlpha();
 
-	/*virtual*/ S32 getNumDeferredPasses();
-	/*virtual*/ void beginDeferredPass(S32 pass);
-	/*virtual*/ void endDeferredPass(S32 pass);
-	/*virtual*/ void renderDeferred(S32 pass);
-
 	/*virtual*/ S32 getNumPostDeferredPasses();
 	/*virtual*/ void beginPostDeferredPass(S32 pass);
 	/*virtual*/ void endPostDeferredPass(S32 pass);
@@ -70,7 +65,7 @@ class LLDrawPoolAlpha: public LLRenderPass
 	void renderGroupAlpha(LLSpatialGroup* group, U32 type, U32 mask, BOOL texture = TRUE);
 	void renderAlpha(U32 mask);
 	void renderAlphaHighlight(U32 mask);
-	
+		
 	static BOOL sShowDebugAlpha;
 
 private:
diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp
index 294cecc7037f1bbf7dc749eb820eefb5a4c8fcfa..075299386e70a039a0389425130ab93c1e2e79f6 100755
--- a/indra/newview/lldrawpoolavatar.cpp
+++ b/indra/newview/lldrawpoolavatar.cpp
@@ -62,6 +62,7 @@ S32 LLDrawPoolAvatar::sDiffuseChannel = 0;
 
 
 static bool is_deferred_render = false;
+static bool is_post_deferred_render = false;
 
 extern BOOL gUseGLPick;
 
@@ -183,6 +184,9 @@ void LLDrawPoolAvatar::beginDeferredPass(S32 pass)
 	case 4:
 		beginDeferredRiggedBump();
 		break;
+	default:
+		beginDeferredRiggedMaterial(pass-5);
+		break;
 	}
 }
 
@@ -215,6 +219,9 @@ void LLDrawPoolAvatar::endDeferredPass(S32 pass)
 	case 4:
 		endDeferredRiggedBump();
 		break;
+	default:
+		endDeferredRiggedMaterial(pass-5);
+		break;
 	}
 }
 
@@ -225,7 +232,7 @@ void LLDrawPoolAvatar::renderDeferred(S32 pass)
 
 S32 LLDrawPoolAvatar::getNumPostDeferredPasses()
 {
-	return 6;
+	return 10;
 }
 
 void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass)
@@ -247,9 +254,12 @@ void LLDrawPoolAvatar::beginPostDeferredPass(S32 pass)
 	case 4:
 		beginRiggedFullbrightAlpha();
 		break;
-	case 5:
+	case 9:
 		beginRiggedGlow();
 		break;
+	default:
+		beginDeferredRiggedMaterialAlpha(pass-5);
+		break;
 	}
 }
 
@@ -275,11 +285,34 @@ void LLDrawPoolAvatar::beginDeferredRiggedAlpha()
 	gPipeline.enableLightsDynamic();
 }
 
+void LLDrawPoolAvatar::beginDeferredRiggedMaterialAlpha(S32 pass)
+{
+	switch (pass)
+	{
+	case 0: pass = 1; break;
+	case 1: pass = 5; break;
+	case 2: pass = 9; break;
+	default: pass = 13; break;
+	}
+
+	pass += LLMaterial::SHADER_COUNT;
+
+	sVertexProgram = &gDeferredMaterialProgram[pass];
+
+	gPipeline.bindDeferredShader(*sVertexProgram);
+	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
+	specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
+	gPipeline.enableLightsDynamic();
+}
+
 void LLDrawPoolAvatar::endDeferredRiggedAlpha()
 {
 	LLVertexBuffer::unbind();
 	gPipeline.unbindDeferredShader(*sVertexProgram);
 	sDiffuseChannel = 0;
+	normal_channel = -1;
+	specular_channel = -1;
 	sVertexProgram = NULL;
 }
 
@@ -305,6 +338,9 @@ void LLDrawPoolAvatar::endPostDeferredPass(S32 pass)
 	case 5:
 		endRiggedGlow();
 		break;
+	default:
+		endDeferredRiggedAlpha();
+		break;
 	}
 }
 
@@ -328,17 +364,23 @@ void LLDrawPoolAvatar::renderPostDeferred(S32 pass)
 		6, //rigged fullbright shiny
 		7, //rigged alpha
 		8, //rigged fullbright alpha
-		9, //rigged glow
+		9, //rigged material alpha 1
+		10,//rigged material alpha 2
+		11,//rigged material alpha 3
+		12,//rigged material alpha 4
+		13, //rigged glow
 	};
 
-	pass = actual_pass[pass];
+	S32 p = actual_pass[pass];
 
 	if (LLPipeline::sImpostorRender)
 	{ //HACK for impostors so actual pass ends up being proper pass
-		pass -= 2;
+		p -= 2;
 	}
 
-	render(pass);
+	is_post_deferred_render = true;
+	render(p);
+	is_post_deferred_render = false;
 }
 
 
@@ -425,12 +467,10 @@ void LLDrawPoolAvatar::renderShadow(S32 pass)
 	}
 	else
 	{
-		renderRigged(avatarp, RIGGED_SIMPLE);
-		renderRigged(avatarp, RIGGED_ALPHA);
-		renderRigged(avatarp, RIGGED_FULLBRIGHT);
-		renderRigged(avatarp, RIGGED_FULLBRIGHT_SHINY);
-		renderRigged(avatarp, RIGGED_SHINY);
-		renderRigged(avatarp, RIGGED_FULLBRIGHT_ALPHA);
+		for (U32 i = 0; i < NUM_RIGGED_PASSES; ++i)
+		{
+			renderRigged(avatarp, i);
+		}
 	}
 }
 
@@ -455,7 +495,7 @@ S32 LLDrawPoolAvatar::getNumDeferredPasses()
 	}
 	else
 	{
-		return 5;
+		return 21;
 	}
 }
 
@@ -839,6 +879,8 @@ void LLDrawPoolAvatar::beginRiggedGlow()
 	{
 		sDiffuseChannel = 0;
 		sVertexProgram->bind();
+
+		sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, LLPipeline::sRenderDeferred ? 2.2f : 1.1f);
 	}
 }
 
@@ -857,7 +899,14 @@ void LLDrawPoolAvatar::beginRiggedFullbright()
 		}
 		else
 		{
-			sVertexProgram = &gSkinnedObjectFullbrightProgram;
+			if (LLPipeline::sRenderDeferred)
+			{
+				sVertexProgram = &gDeferredSkinnedFullbrightProgram;
+			}
+			else
+			{
+				sVertexProgram = &gSkinnedObjectFullbrightProgram;
+			}
 		}
 	}
 	else
@@ -876,6 +925,15 @@ void LLDrawPoolAvatar::beginRiggedFullbright()
 	{
 		sDiffuseChannel = 0;
 		sVertexProgram->bind();
+
+		if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred)
+		{
+			sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
+		} 
+		else 
+		{
+			sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+		}
 	}
 }
 
@@ -942,7 +1000,14 @@ void LLDrawPoolAvatar::beginRiggedFullbrightShiny()
 		}
 		else
 		{
-			sVertexProgram = &gSkinnedObjectFullbrightShinyProgram;
+			if (LLPipeline::sRenderDeferred)
+			{
+				sVertexProgram = &gDeferredSkinnedFullbrightShinyProgram;
+			}
+			else
+			{
+				sVertexProgram = &gSkinnedObjectFullbrightShinyProgram;
+			}
 		}
 	}
 	else
@@ -957,11 +1022,19 @@ void LLDrawPoolAvatar::beginRiggedFullbrightShiny()
 		}
 	}
 
-
 	if (sShaderLevel > 0 || gPipeline.canUseVertexShaders())
 	{
 		sVertexProgram->bind();
 		LLDrawPoolBump::bindCubeMap(sVertexProgram, 2, sDiffuseChannel, cube_channel, false);
+
+		if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred)
+		{
+			sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
+		} 
+		else 
+		{
+			sVertexProgram->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+		}
 	}
 }
 
@@ -1010,6 +1083,42 @@ void LLDrawPoolAvatar::endDeferredRiggedBump()
 	sVertexProgram = NULL;
 }
 
+void LLDrawPoolAvatar::beginDeferredRiggedMaterial(S32 pass)
+{
+	if (pass == 1 ||
+		pass == 5 ||
+		pass == 9 ||
+		pass == 13)
+	{ //skip alpha passes
+		return;
+	}
+	sVertexProgram = &gDeferredMaterialProgram[pass+LLMaterial::SHADER_COUNT];
+	sVertexProgram->bind();
+	normal_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::BUMP_MAP);
+	specular_channel = sVertexProgram->enableTexture(LLViewerShaderMgr::SPECULAR_MAP);
+	sDiffuseChannel = sVertexProgram->enableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+}
+
+void LLDrawPoolAvatar::endDeferredRiggedMaterial(S32 pass)
+{
+	if (pass == 1 ||
+		pass == 5 ||
+		pass == 9 ||
+		pass == 13)
+	{
+		return;
+	}
+
+	LLVertexBuffer::unbind();
+	sVertexProgram->disableTexture(LLViewerShaderMgr::BUMP_MAP);
+	sVertexProgram->disableTexture(LLViewerShaderMgr::SPECULAR_MAP);
+	sVertexProgram->disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+	sVertexProgram->unbind();
+	normal_channel = -1;
+	sDiffuseChannel = 0;
+	sVertexProgram = NULL;
+}
+
 void LLDrawPoolAvatar::beginDeferredSkinned()
 {
 	sShaderLevel = mVertexShaderLevel;
@@ -1167,6 +1276,22 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 		else
 		{
 			renderRiggedSimple(avatarp);
+
+			if (LLPipeline::sRenderDeferred)
+			{ //render "simple" materials
+				renderRigged(avatarp, RIGGED_MATERIAL);
+				renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_MASK);
+				renderRigged(avatarp, RIGGED_MATERIAL_ALPHA_EMISSIVE);
+				renderRigged(avatarp, RIGGED_NORMMAP);
+				renderRigged(avatarp, RIGGED_NORMMAP_MASK);
+				renderRigged(avatarp, RIGGED_NORMMAP_EMISSIVE);	
+				renderRigged(avatarp, RIGGED_SPECMAP);
+				renderRigged(avatarp, RIGGED_SPECMAP_MASK);
+				renderRigged(avatarp, RIGGED_SPECMAP_EMISSIVE);
+				renderRigged(avatarp, RIGGED_NORMSPEC);
+				renderRigged(avatarp, RIGGED_NORMSPEC_MASK);
+				renderRigged(avatarp, RIGGED_NORMSPEC_EMISSIVE);
+			}
 		}
 		return;
 	}
@@ -1185,9 +1310,27 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 		return;
 	}
 
+	if (is_deferred_render && pass >= 5 && pass <= 21)
+	{
+		S32 p = pass-5;
+
+		if (p != 1 &&
+			p != 5 &&
+			p != 9 &&
+			p != 13)
+		{
+			renderDeferredRiggedMaterial(avatarp, p);
+		}
+		return;
+	}
+
+
+
+
 	if (pass == 5)
 	{
 		renderRiggedShinySimple(avatarp);
+				
 		return;
 	}
 
@@ -1197,11 +1340,29 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 		return;
 	}
 
-	if (pass >= 7 && pass < 9)
+	if (pass >= 7 && pass < 13)
 	{
 		if (pass == 7)
 		{
 			renderRiggedAlpha(avatarp);
+
+			if (LLPipeline::sRenderDeferred && !is_post_deferred_render)
+			{ //render transparent materials under water
+				LLGLEnable blend(GL_BLEND);
+
+				gGL.setColorMask(true, true);
+				gGL.blendFunc(LLRender::BF_SOURCE_ALPHA,
+								LLRender::BF_ONE_MINUS_SOURCE_ALPHA,
+								LLRender::BF_ZERO,
+								LLRender::BF_ONE_MINUS_SOURCE_ALPHA);
+
+				renderRigged(avatarp, RIGGED_MATERIAL_ALPHA);
+				renderRigged(avatarp, RIGGED_SPECMAP_BLEND);
+				renderRigged(avatarp, RIGGED_NORMMAP_BLEND);
+				renderRigged(avatarp, RIGGED_NORMSPEC_BLEND);
+
+				gGL.setColorMask(true, false);
+			}
 			return;
 		}
 
@@ -1210,9 +1371,32 @@ void LLDrawPoolAvatar::renderAvatars(LLVOAvatar* single_avatar, S32 pass)
 			renderRiggedFullbrightAlpha(avatarp);
 			return;
 		}
+
+		if (LLPipeline::sRenderDeferred && is_post_deferred_render)
+		{
+			S32 p = 0;
+			switch (pass)
+			{
+			case 9: p = 1; break;
+			case 10: p = 5; break;
+			case 11: p = 9; break;
+			case 12: p = 13; break;
+			}
+
+			{
+				LLGLEnable blend(GL_BLEND);
+				renderDeferredRiggedMaterial(avatarp, p);
+			}
+			return;
+		}
+		else if (pass == 9)
+		{
+			renderRiggedGlow(avatarp);
+			return;
+		}
 	}
 
-	if (pass == 9)
+	if (pass == 13)
 	{
 		renderRiggedGlow(avatarp);
 		
@@ -1474,9 +1658,11 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 		{
 			if (sShaderLevel > 0)
 			{ //upload matrix palette to shader
-				LLMatrix4 mat[64];
+				LLMatrix4 mat[32];
+
+				U32 count = llmin((U32) skin->mJointNames.size(), (U32) 32);
 
-				for (U32 i = 0; i < skin->mJointNames.size(); ++i)
+				for (U32 i = 0; i < count; ++i)
 				{
 					LLJoint* joint = avatar->getJoint(skin->mJointNames[i]);
 					if (joint)
@@ -1489,7 +1675,7 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 				stop_glerror();
 
 				LLDrawPoolAvatar::sVertexProgram->uniformMatrix4fv("matrixPalette", 
-					skin->mJointNames.size(),
+					count,
 					FALSE,
 					(GLfloat*) mat[0].mMatrix);
 				
@@ -1510,10 +1696,59 @@ void LLDrawPoolAvatar::renderRigged(LLVOAvatar* avatar, U32 type, bool glow)
 				gGL.diffuseColor4f(0,0,0,face->getTextureEntry()->getGlow());
 			}*/
 
-			gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture());
-			if (normal_channel > -1)
+			const LLTextureEntry* te = face->getTextureEntry();
+			LLMaterial* mat = te->getMaterialParams().get();
+
+			if (mat)
 			{
-				LLDrawPoolBump::bindBumpMap(face, normal_channel);
+				gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture(LLRender::DIFFUSE_MAP));
+				gGL.getTexUnit(normal_channel)->bind(face->getTexture(LLRender::NORMAL_MAP));
+				gGL.getTexUnit(specular_channel)->bind(face->getTexture(LLRender::SPECULAR_MAP));
+
+				LLColor4 col = mat->getSpecularLightColor();
+				F32 spec = mat->getSpecularLightExponent()/255.f;
+
+				F32 env = mat->getEnvironmentIntensity()/255.f;
+
+				if (mat->getSpecularID().isNull())
+				{
+					env = te->getShiny()*0.25f;
+					col.set(env,env,env,0);
+					spec = env;
+				}
+		
+				BOOL fullbright = te->getFullbright();
+
+				sVertexProgram->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, fullbright ? 1.f : 0.f);
+				sVertexProgram->uniform4f(LLShaderMgr::SPECULAR_COLOR, col.mV[0], col.mV[1], col.mV[2], spec);
+				sVertexProgram->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, env);
+
+				if (mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK)
+				{
+					sVertexProgram->setMinimumAlpha(mat->getAlphaMaskCutoff()/255.f);
+				}
+				else
+				{
+					sVertexProgram->setMinimumAlpha(0.f);
+				}
+
+				for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i)
+				{
+					LLViewerTexture* tex = face->getTexture(i);
+					if (tex)
+					{
+						tex->addTextureStats(avatar->getPixelArea());
+					}
+				}
+			}
+			else
+			{
+				gGL.getTexUnit(sDiffuseChannel)->bind(face->getTexture());
+				sVertexProgram->setMinimumAlpha(0.f);
+				if (normal_channel > -1)
+				{
+					LLDrawPoolBump::bindBumpMap(face, normal_channel);
+				}
 			}
 
 			if (face->mTextureMatrix)
@@ -1545,6 +1780,11 @@ void LLDrawPoolAvatar::renderDeferredRiggedBump(LLVOAvatar* avatar)
 	renderRigged(avatar, RIGGED_DEFERRED_BUMP);
 }
 
+void LLDrawPoolAvatar::renderDeferredRiggedMaterial(LLVOAvatar* avatar, S32 pass)
+{
+	renderRigged(avatar, pass);
+}
+
 static LLFastTimer::DeclareTimer FTM_RIGGED_VBO("Rigged VBO");
 
 void LLDrawPoolAvatar::updateRiggedVertexBuffers(LLVOAvatar* avatar)
diff --git a/indra/newview/lldrawpoolavatar.h b/indra/newview/lldrawpoolavatar.h
index 69e306885893797c00e5b222c59d338d59a43739..7d0368a9459d7b7363228e12e7968730e490f14b 100755
--- a/indra/newview/lldrawpoolavatar.h
+++ b/indra/newview/lldrawpoolavatar.h
@@ -75,7 +75,7 @@ class LLDrawPoolAvatar : public LLFacePool
 	/*virtual*/ void beginDeferredPass(S32 pass);
 	/*virtual*/ void endDeferredPass(S32 pass);
 	/*virtual*/ void renderDeferred(S32 pass);
-
+	
 	/*virtual*/ S32 getNumPostDeferredPasses();
 	/*virtual*/ void beginPostDeferredPass(S32 pass);
 	/*virtual*/ void endPostDeferredPass(S32 pass);
@@ -113,6 +113,8 @@ class LLDrawPoolAvatar : public LLFacePool
 	void beginRiggedFullbrightAlpha();
 	void beginRiggedGlow();
 	void beginDeferredRiggedAlpha();
+	void beginDeferredRiggedMaterial(S32 pass);
+	void beginDeferredRiggedMaterialAlpha(S32 pass);
 
 	void endRiggedSimple();
 	void endRiggedFullbright();
@@ -122,6 +124,8 @@ class LLDrawPoolAvatar : public LLFacePool
 	void endRiggedFullbrightAlpha();
 	void endRiggedGlow();
 	void endDeferredRiggedAlpha();
+	void endDeferredRiggedMaterial(S32 pass);
+	void endDeferredRiggedMaterialAlpha(S32 pass);
 
 	void beginDeferredRiggedSimple();
 	void beginDeferredRiggedBump();
@@ -146,10 +150,27 @@ class LLDrawPoolAvatar : public LLFacePool
 	void renderRiggedGlow(LLVOAvatar* avatar);
 	void renderDeferredRiggedSimple(LLVOAvatar* avatar);
 	void renderDeferredRiggedBump(LLVOAvatar* avatar);
-
+	void renderDeferredRiggedMaterial(LLVOAvatar* avatar, S32 pass);
+	
 	typedef enum
 	{
-		RIGGED_SIMPLE = 0,
+		RIGGED_MATERIAL=0,
+		RIGGED_MATERIAL_ALPHA,
+		RIGGED_MATERIAL_ALPHA_MASK,
+		RIGGED_MATERIAL_ALPHA_EMISSIVE,
+		RIGGED_SPECMAP,
+		RIGGED_SPECMAP_BLEND,
+		RIGGED_SPECMAP_MASK,
+		RIGGED_SPECMAP_EMISSIVE,
+		RIGGED_NORMMAP,
+		RIGGED_NORMMAP_BLEND,
+		RIGGED_NORMMAP_MASK,
+		RIGGED_NORMMAP_EMISSIVE,
+		RIGGED_NORMSPEC,
+		RIGGED_NORMSPEC_BLEND,
+		RIGGED_NORMSPEC_MASK,
+		RIGGED_NORMSPEC_EMISSIVE,
+		RIGGED_SIMPLE,
 		RIGGED_FULLBRIGHT,
 		RIGGED_SHINY,
 		RIGGED_FULLBRIGHT_SHINY,
@@ -164,6 +185,48 @@ class LLDrawPoolAvatar : public LLFacePool
 
 	typedef enum
 	{
+		RIGGED_MATERIAL_MASK =
+						LLVertexBuffer::MAP_VERTEX | 
+						LLVertexBuffer::MAP_NORMAL | 
+						LLVertexBuffer::MAP_TEXCOORD0 |
+						LLVertexBuffer::MAP_COLOR |
+						LLVertexBuffer::MAP_WEIGHT4,
+		RIGGED_MATERIAL_ALPHA_VMASK = RIGGED_MATERIAL_MASK,
+		RIGGED_MATERIAL_ALPHA_MASK_MASK = RIGGED_MATERIAL_MASK,
+		RIGGED_MATERIAL_ALPHA_EMISSIVE_MASK = RIGGED_MATERIAL_MASK,
+		RIGGED_SPECMAP_VMASK =
+						LLVertexBuffer::MAP_VERTEX | 
+						LLVertexBuffer::MAP_NORMAL | 
+						LLVertexBuffer::MAP_TEXCOORD0 |
+						LLVertexBuffer::MAP_TEXCOORD2 |
+						LLVertexBuffer::MAP_COLOR |
+						LLVertexBuffer::MAP_WEIGHT4,
+		RIGGED_SPECMAP_BLEND_MASK = RIGGED_SPECMAP_VMASK,
+		RIGGED_SPECMAP_MASK_MASK = RIGGED_SPECMAP_VMASK,
+		RIGGED_SPECMAP_EMISSIVE_MASK = RIGGED_SPECMAP_VMASK,
+		RIGGED_NORMMAP_VMASK =
+						LLVertexBuffer::MAP_VERTEX | 
+						LLVertexBuffer::MAP_NORMAL | 
+						LLVertexBuffer::MAP_TANGENT | 
+						LLVertexBuffer::MAP_TEXCOORD0 |
+						LLVertexBuffer::MAP_TEXCOORD1 |
+						LLVertexBuffer::MAP_COLOR |
+						LLVertexBuffer::MAP_WEIGHT4,
+		RIGGED_NORMMAP_BLEND_MASK = RIGGED_NORMMAP_VMASK,
+		RIGGED_NORMMAP_MASK_MASK = RIGGED_NORMMAP_VMASK,
+		RIGGED_NORMMAP_EMISSIVE_MASK = RIGGED_NORMMAP_VMASK,
+		RIGGED_NORMSPEC_VMASK =
+						LLVertexBuffer::MAP_VERTEX | 
+						LLVertexBuffer::MAP_NORMAL | 
+						LLVertexBuffer::MAP_TANGENT | 
+						LLVertexBuffer::MAP_TEXCOORD0 |
+						LLVertexBuffer::MAP_TEXCOORD1 |
+						LLVertexBuffer::MAP_TEXCOORD2 |
+						LLVertexBuffer::MAP_COLOR |
+						LLVertexBuffer::MAP_WEIGHT4,
+		RIGGED_NORMSPEC_BLEND_MASK = RIGGED_NORMSPEC_VMASK,
+		RIGGED_NORMSPEC_MASK_MASK = RIGGED_NORMSPEC_VMASK,
+		RIGGED_NORMSPEC_EMISSIVE_MASK = RIGGED_NORMSPEC_VMASK,
 		RIGGED_SIMPLE_MASK = LLVertexBuffer::MAP_VERTEX | 
 							 LLVertexBuffer::MAP_NORMAL | 
 							 LLVertexBuffer::MAP_TEXCOORD0 |
@@ -184,7 +247,7 @@ class LLDrawPoolAvatar : public LLFacePool
 		RIGGED_DEFERRED_BUMP_MASK = LLVertexBuffer::MAP_VERTEX | 
 							 LLVertexBuffer::MAP_NORMAL | 
 							 LLVertexBuffer::MAP_TEXCOORD0 |
-							 LLVertexBuffer::MAP_BINORMAL |
+							 LLVertexBuffer::MAP_TANGENT |
 							 LLVertexBuffer::MAP_COLOR |
 							 LLVertexBuffer::MAP_WEIGHT4,
 		RIGGED_DEFERRED_SIMPLE_MASK = LLVertexBuffer::MAP_VERTEX | 
diff --git a/indra/newview/lldrawpoolbump.cpp b/indra/newview/lldrawpoolbump.cpp
index e8d43c86312fe6658e19929daec7bbe5ad6987f4..155e289c9d1385fd28077a23ab00d0ae411da70f 100755
--- a/indra/newview/lldrawpoolbump.cpp
+++ b/indra/newview/lldrawpoolbump.cpp
@@ -153,7 +153,7 @@ void LLStandardBumpmap::addstandard()
 		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mLabel = label;
 		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage = 
 			LLViewerTextureManager::getFetchedTexture(LLUUID(bump_image_id));	
-		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setBoostLevel(LLGLTexture::BOOST_BUMP) ;
+		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setBoostLevel(LLGLTexture::LOCAL) ;
 		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->setLoadedCallback(LLBumpImageList::onSourceStandardLoaded, 0, TRUE, FALSE, NULL, NULL );
 		gStandardBumpmapList[LLStandardBumpmap::sStandardBumpmapCount].mImage->forceToSaveRawImage(0) ;
 		LLStandardBumpmap::sStandardBumpmapCount++;
@@ -449,9 +449,6 @@ void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32&
 	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
 	if( cube_map )
 	{
-		cube_map->disable();
-		cube_map->restoreMatrix();
-
 		if (!invisible && shader_level > 1)
 		{
 			shader->disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
@@ -464,6 +461,8 @@ void LLDrawPoolBump::unbindCubeMap(LLGLSLShader* shader, S32 shader_level, S32&
 				}
 			}
 		}
+		cube_map->disable();
+		cube_map->restoreMatrix();
 	}
 
 	if (!LLGLSLShader::sNoFixedFunction)
@@ -514,7 +513,14 @@ void LLDrawPoolBump::beginFullbrightShiny()
 	}
 	else
 	{
-		shader = &gObjectFullbrightShinyProgram;
+		if (LLPipeline::sRenderDeferred)
+		{
+			shader = &gDeferredFullbrightShinyProgram;
+		}
+		else
+		{
+			shader = &gObjectFullbrightShinyProgram;
+		}
 	}
 
 	LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
@@ -850,7 +856,7 @@ void LLDrawPoolBump::renderDeferred(S32 pass)
 	LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type);
 	LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type);
 
-	U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_BINORMAL | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR;
+	U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_COLOR;
 	
 	for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i)	
 	{
@@ -915,6 +921,8 @@ void LLBumpImageList::init()
 	llassert( mDarknessEntries.size() == 0 );
 
 	LLStandardBumpmap::init();
+
+	LLStandardBumpmap::restoreGL();
 }
 
 void LLBumpImageList::clear()
diff --git a/indra/newview/lldrawpoolmaterials.cpp b/indra/newview/lldrawpoolmaterials.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..08a36bddf181fe7b18666eb18f239218c356fdef
--- /dev/null
+++ b/indra/newview/lldrawpoolmaterials.cpp
@@ -0,0 +1,217 @@
+/** 
+ * @file lldrawpool.cpp
+ * @brief LLDrawPoolMaterials class implementation
+ * @author Jonathan "Geenz" Goodman
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, 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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "lldrawpoolmaterials.h"
+#include "llviewershadermgr.h"
+#include "pipeline.h"
+
+S32 diffuse_channel = -1;
+
+LLDrawPoolMaterials::LLDrawPoolMaterials()
+:  LLRenderPass(LLDrawPool::POOL_MATERIALS)
+{
+	
+}
+
+void LLDrawPoolMaterials::prerender()
+{
+	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT); 
+}
+
+S32 LLDrawPoolMaterials::getNumDeferredPasses()
+{
+	return 12;
+}
+
+void LLDrawPoolMaterials::beginDeferredPass(S32 pass)
+{
+	U32 shader_idx[] = 
+	{
+		0, //LLRenderPass::PASS_MATERIAL,
+		//1, //LLRenderPass::PASS_MATERIAL_ALPHA,
+		2, //LLRenderPass::PASS_MATERIAL_ALPHA_MASK,
+		3, //LLRenderPass::PASS_MATERIAL_ALPHA_GLOW,
+		4, //LLRenderPass::PASS_SPECMAP,
+		//5, //LLRenderPass::PASS_SPECMAP_BLEND,
+		6, //LLRenderPass::PASS_SPECMAP_MASK,
+		7, //LLRenderPass::PASS_SPECMAP_GLOW,
+		8, //LLRenderPass::PASS_NORMMAP,
+		//9, //LLRenderPass::PASS_NORMMAP_BLEND,
+		10, //LLRenderPass::PASS_NORMMAP_MASK,
+		11, //LLRenderPass::PASS_NORMMAP_GLOW,
+		12, //LLRenderPass::PASS_NORMSPEC,
+		//13, //LLRenderPass::PASS_NORMSPEC_BLEND,
+		14, //LLRenderPass::PASS_NORMSPEC_MASK,
+		15, //LLRenderPass::PASS_NORMSPEC_GLOW,
+	};
+	
+	mShader = &(gDeferredMaterialProgram[shader_idx[pass]]);
+	mShader->bind();
+
+	diffuse_channel = mShader->enableTexture(LLShaderMgr::DIFFUSE_MAP);
+		
+	LLFastTimer t(FTM_RENDER_MATERIALS);
+}
+
+void LLDrawPoolMaterials::endDeferredPass(S32 pass)
+{
+	LLFastTimer t(FTM_RENDER_MATERIALS);
+
+	mShader->unbind();
+
+	LLRenderPass::endRenderPass(pass);
+}
+
+void LLDrawPoolMaterials::renderDeferred(S32 pass)
+{
+	U32 type_list[] = 
+	{
+		LLRenderPass::PASS_MATERIAL,
+		//LLRenderPass::PASS_MATERIAL_ALPHA,
+		LLRenderPass::PASS_MATERIAL_ALPHA_MASK,
+		LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE,
+		LLRenderPass::PASS_SPECMAP,
+		//LLRenderPass::PASS_SPECMAP_BLEND,
+		LLRenderPass::PASS_SPECMAP_MASK,
+		LLRenderPass::PASS_SPECMAP_EMISSIVE,
+		LLRenderPass::PASS_NORMMAP,
+		//LLRenderPass::PASS_NORMMAP_BLEND,
+		LLRenderPass::PASS_NORMMAP_MASK,
+		LLRenderPass::PASS_NORMMAP_EMISSIVE,
+		LLRenderPass::PASS_NORMSPEC,
+		//LLRenderPass::PASS_NORMSPEC_BLEND,
+		LLRenderPass::PASS_NORMSPEC_MASK,
+		LLRenderPass::PASS_NORMSPEC_EMISSIVE,
+	};
+
+	llassert(pass < sizeof(type_list)/sizeof(U32));
+
+	U32 type = type_list[pass];
+
+	U32 mask = mShader->mAttributeMask;
+
+	LLCullResult::drawinfo_iterator begin = gPipeline.beginRenderMap(type);
+	LLCullResult::drawinfo_iterator end = gPipeline.endRenderMap(type);
+	
+	for (LLCullResult::drawinfo_iterator i = begin; i != end; ++i)
+	{
+		LLDrawInfo& params = **i;
+		
+		mShader->uniform4f(LLShaderMgr::SPECULAR_COLOR, params.mSpecColor.mV[0], params.mSpecColor.mV[1], params.mSpecColor.mV[2], params.mSpecColor.mV[3]);
+		mShader->uniform1f(LLShaderMgr::ENVIRONMENT_INTENSITY, params.mEnvIntensity);
+		
+		if (params.mNormalMap)
+		{
+			params.mNormalMap->addTextureStats(params.mVSize);
+			bindNormalMap(params.mNormalMap);
+		}
+		
+		if (params.mSpecularMap)
+		{
+			params.mSpecularMap->addTextureStats(params.mVSize);
+			bindSpecularMap(params.mSpecularMap);
+		}
+		
+		mShader->setMinimumAlpha(params.mAlphaMaskCutoff);
+		mShader->uniform1f(LLShaderMgr::EMISSIVE_BRIGHTNESS, params.mFullbright ? 1.f : 0.f);
+
+		pushBatch(params, mask, TRUE);
+	}
+}
+
+void LLDrawPoolMaterials::bindSpecularMap(LLViewerTexture* tex)
+{
+	mShader->bindTexture(LLShaderMgr::SPECULAR_MAP, tex);
+}
+
+void LLDrawPoolMaterials::bindNormalMap(LLViewerTexture* tex)
+{
+	mShader->bindTexture(LLShaderMgr::BUMP_MAP, tex);
+}
+
+void LLDrawPoolMaterials::pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures)
+{
+	applyModelMatrix(params);
+	
+	bool tex_setup = false;
+	
+	if (batch_textures && params.mTextureList.size() > 1)
+	{
+		for (U32 i = 0; i < params.mTextureList.size(); ++i)
+		{
+			if (params.mTextureList[i].notNull())
+			{
+				gGL.getTexUnit(i)->bind(params.mTextureList[i], TRUE);
+			}
+		}
+	}
+	else
+	{ //not batching textures or batch has only 1 texture -- might need a texture matrix
+		if (params.mTextureMatrix)
+		{
+			//if (mShiny)
+			{
+				gGL.getTexUnit(0)->activate();
+				gGL.matrixMode(LLRender::MM_TEXTURE);
+			}
+			
+			gGL.loadMatrix((GLfloat*) params.mTextureMatrix->mMatrix);
+			gPipeline.mTextureMatrixOps++;
+			
+			tex_setup = true;
+		}
+		
+		if (mVertexShaderLevel > 1 && texture)
+		{
+			if (params.mTexture.notNull())
+			{
+				gGL.getTexUnit(diffuse_channel)->bind(params.mTexture);
+				params.mTexture->addTextureStats(params.mVSize);
+			}
+			else
+			{
+				gGL.getTexUnit(diffuse_channel)->unbind(LLTexUnit::TT_TEXTURE);
+			}
+		}
+	}
+	
+	if (params.mGroup)
+	{
+		params.mGroup->rebuildMesh();
+	}
+	params.mVertexBuffer->setBuffer(mask);
+	params.mVertexBuffer->drawRange(params.mDrawMode, params.mStart, params.mEnd, params.mCount, params.mOffset);
+	gPipeline.addTrianglesDrawn(params.mCount, params.mDrawMode);
+	if (tex_setup)
+	{
+		gGL.getTexUnit(0)->activate();
+		gGL.loadIdentity();
+		gGL.matrixMode(LLRender::MM_MODELVIEW);
+	}
+}
diff --git a/indra/newview/lldrawpoolmaterials.h b/indra/newview/lldrawpoolmaterials.h
new file mode 100644
index 0000000000000000000000000000000000000000..eae1aba87cd8ed375b7f278711ddbb5a56b53d78
--- /dev/null
+++ b/indra/newview/lldrawpoolmaterials.h
@@ -0,0 +1,75 @@
+/** 
+ * @file lldrawpoolmaterials.h
+ * @brief LLDrawPoolMaterials class definition
+ * @author Jonathan "Geenz" Goodman
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLDRAWPOOLMATERIALS_H
+#define LL_LLDRAWPOOLMATERIALS_H
+
+#include "v4coloru.h"
+#include "v2math.h"
+#include "v3math.h"
+#include "llvertexbuffer.h"
+#include "lldrawpool.h"
+
+class LLViewerTexture;
+class LLDrawInfo;
+class LLGLSLShader;
+
+class LLDrawPoolMaterials : public LLRenderPass
+{
+	LLGLSLShader *mShader;
+public:
+	LLDrawPoolMaterials();
+	
+	enum
+	{
+		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
+		LLVertexBuffer::MAP_NORMAL |
+		LLVertexBuffer::MAP_TEXCOORD0 |
+		LLVertexBuffer::MAP_TEXCOORD1 |
+		LLVertexBuffer::MAP_TEXCOORD2 |
+		LLVertexBuffer::MAP_COLOR |
+		LLVertexBuffer::MAP_TANGENT
+	};
+	
+	/*virtual*/ U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
+	
+	/*virtual*/ void render(S32 pass = 0) { }
+	/*virtual*/ S32	 getNumPasses() {return 0;}
+	/*virtual*/ void prerender();
+	
+	/*virtual*/ S32 getNumDeferredPasses();
+	/*virtual*/ void beginDeferredPass(S32 pass);
+	/*virtual*/ void endDeferredPass(S32 pass);
+	/*virtual*/ void renderDeferred(S32 pass);
+	
+	void bindSpecularMap(LLViewerTexture* tex);
+	void bindNormalMap(LLViewerTexture* tex);
+	
+	/*virtual*/ void pushBatch(LLDrawInfo& params, U32 mask, BOOL texture, BOOL batch_textures = FALSE);
+};
+
+#endif //LL_LLDRAWPOOLMATERIALS_H
diff --git a/indra/newview/lldrawpoolsimple.cpp b/indra/newview/lldrawpoolsimple.cpp
index 6e0ea78af2b2d326dbb639a943852d51cf688ec9..2cf9d833c60520d3f8d0f016c23a1d2394eaabb0 100755
--- a/indra/newview/lldrawpoolsimple.cpp
+++ b/indra/newview/lldrawpoolsimple.cpp
@@ -47,6 +47,7 @@ static LLFastTimer::DeclareTimer FTM_RENDER_GRASS_DEFERRED("Deferred Grass");
 void LLDrawPoolGlow::beginPostDeferredPass(S32 pass)
 {
 	gDeferredEmissiveProgram.bind();
+	gDeferredEmissiveProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
 }
 
 static LLFastTimer::DeclareTimer FTM_RENDER_GLOW_PUSH("Glow Push");
@@ -110,6 +111,7 @@ void LLDrawPoolGlow::render(S32 pass)
 	
 	LLGLSLShader* shader = LLPipeline::sUnderWaterRender ? &gObjectEmissiveWaterProgram : &gObjectEmissiveProgram;
 	shader->bind();
+	shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.f);
 
 	LLGLDepthTest depth(GL_TRUE, GL_FALSE);
 	gGL.setColorMask(false, true);
@@ -198,7 +200,11 @@ void LLDrawPoolSimple::render(S32 pass)
 			if (LLPipeline::sRenderDeferred)
 			{ //if deferred rendering is enabled, bump faces aren't registered as simple
 				//render bump faces here as simple so bump faces will appear under water
-				pushBatches(LLRenderPass::PASS_BUMP, mask, TRUE, TRUE);
+				pushBatches(LLRenderPass::PASS_BUMP, mask, TRUE, TRUE);			
+				pushBatches(LLRenderPass::PASS_MATERIAL, mask, TRUE, TRUE);
+				pushBatches(LLRenderPass::PASS_SPECMAP, mask, TRUE, TRUE);
+				pushBatches(LLRenderPass::PASS_NORMMAP, mask, TRUE, TRUE);
+				pushBatches(LLRenderPass::PASS_NORMSPEC, mask, TRUE, TRUE);		
 			}
 		}
 		else
@@ -210,6 +216,169 @@ void LLDrawPoolSimple::render(S32 pass)
 	}
 }
 
+
+
+
+
+
+
+
+
+
+static LLFastTimer::DeclareTimer FTM_RENDER_ALPHA_MASK("Alpha Mask");
+
+LLDrawPoolAlphaMask::LLDrawPoolAlphaMask() :
+	LLRenderPass(POOL_ALPHA_MASK)
+{
+}
+
+void LLDrawPoolAlphaMask::prerender()
+{
+	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
+}
+
+void LLDrawPoolAlphaMask::beginRenderPass(S32 pass)
+{
+	LLFastTimer t(FTM_RENDER_ALPHA_MASK);
+
+	if (LLPipeline::sUnderWaterRender)
+	{
+		simple_shader = &gObjectSimpleWaterAlphaMaskProgram;
+	}
+	else
+	{
+		simple_shader = &gObjectSimpleAlphaMaskProgram;
+	}
+
+	if (mVertexShaderLevel > 0)
+	{
+		simple_shader->bind();
+	}
+	else 
+	{
+		// don't use shaders!
+		if (gGLManager.mHasShaderObjects)
+		{
+			LLGLSLShader::bindNoShader();
+		}		
+	}
+}
+
+void LLDrawPoolAlphaMask::endRenderPass(S32 pass)
+{
+	LLFastTimer t(FTM_RENDER_ALPHA_MASK);
+	stop_glerror();
+	LLRenderPass::endRenderPass(pass);
+	stop_glerror();
+	if (mVertexShaderLevel > 0)
+	{
+		simple_shader->unbind();
+	}
+}
+
+void LLDrawPoolAlphaMask::render(S32 pass)
+{
+	LLGLDisable blend(GL_BLEND);
+	LLFastTimer t(FTM_RENDER_ALPHA_MASK);
+	
+	if (mVertexShaderLevel > 0)
+	{
+		simple_shader->bind();
+		simple_shader->setMinimumAlpha(0.33f);
+
+		pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+		pushMaskBatches(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+		pushMaskBatches(LLRenderPass::PASS_SPECMAP_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+		pushMaskBatches(LLRenderPass::PASS_NORMMAP_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+		pushMaskBatches(LLRenderPass::PASS_NORMSPEC_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+	}
+	else
+	{
+		LLGLEnable test(GL_ALPHA_TEST);
+		pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask(), TRUE, FALSE);
+		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); //OK
+	}
+}
+
+LLDrawPoolFullbrightAlphaMask::LLDrawPoolFullbrightAlphaMask() :
+	LLRenderPass(POOL_FULLBRIGHT_ALPHA_MASK)
+{
+}
+
+void LLDrawPoolFullbrightAlphaMask::prerender()
+{
+	mVertexShaderLevel = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT);
+}
+
+void LLDrawPoolFullbrightAlphaMask::beginRenderPass(S32 pass)
+{
+	LLFastTimer t(FTM_RENDER_ALPHA_MASK);
+
+	if (LLPipeline::sUnderWaterRender)
+	{
+		simple_shader = &gObjectFullbrightWaterAlphaMaskProgram;
+	}
+	else
+	{
+		simple_shader = &gObjectFullbrightAlphaMaskProgram;
+	}
+
+	if (mVertexShaderLevel > 0)
+	{
+		simple_shader->bind();
+	}
+	else 
+	{
+		// don't use shaders!
+		if (gGLManager.mHasShaderObjects)
+		{
+			LLGLSLShader::bindNoShader();
+		}		
+	}
+}
+
+void LLDrawPoolFullbrightAlphaMask::endRenderPass(S32 pass)
+{
+	LLFastTimer t(FTM_RENDER_ALPHA_MASK);
+	stop_glerror();
+	LLRenderPass::endRenderPass(pass);
+	stop_glerror();
+	if (mVertexShaderLevel > 0)
+	{
+		simple_shader->unbind();
+	}
+}
+
+void LLDrawPoolFullbrightAlphaMask::render(S32 pass)
+{
+	LLFastTimer t(FTM_RENDER_ALPHA_MASK);
+
+	if (mVertexShaderLevel > 0)
+	{
+		if (simple_shader)
+		{
+			simple_shader->bind();
+			simple_shader->setMinimumAlpha(0.33f);
+			if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred)
+			{
+				simple_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
+			} else {
+				simple_shader->uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+			}
+		}
+		pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+		//LLGLSLShader::bindNoShader();
+	}
+	else
+	{
+		LLGLEnable test(GL_ALPHA_TEST);
+		gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
+		pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, getVertexDataMask(), TRUE, FALSE);
+		gPipeline.enableLightsDynamic();
+		gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT); //OK
+	}
+}
+
 //===============================
 //DEFERRED IMPLEMENTATION
 //===============================
@@ -239,6 +408,28 @@ void LLDrawPoolSimple::renderDeferred(S32 pass)
 	}
 }
 
+static LLFastTimer::DeclareTimer FTM_RENDER_ALPHA_MASK_DEFERRED("Deferred Alpha Mask");
+
+void LLDrawPoolAlphaMask::beginDeferredPass(S32 pass)
+{
+	
+}
+
+void LLDrawPoolAlphaMask::endDeferredPass(S32 pass)
+{
+	
+}
+
+void LLDrawPoolAlphaMask::renderDeferred(S32 pass)
+{
+	LLFastTimer t(FTM_RENDER_ALPHA_MASK_DEFERRED);
+	gDeferredDiffuseAlphaMaskProgram.bind();
+	gDeferredDiffuseAlphaMaskProgram.setMinimumAlpha(0.33f);
+	pushMaskBatches(LLRenderPass::PASS_ALPHA_MASK, getVertexDataMask() | LLVertexBuffer::MAP_TEXTURE_INDEX, TRUE, TRUE);
+	gDeferredDiffuseAlphaMaskProgram.unbind();			
+}
+
+
 // grass drawpool
 LLDrawPoolGrass::LLDrawPoolGrass() :
  LLRenderPass(POOL_GRASS)
@@ -403,14 +594,24 @@ void LLDrawPoolFullbright::render(S32 pass)
 	{
 		fullbright_shader->bind();
 		fullbright_shader->uniform1f(LLViewerShaderMgr::FULLBRIGHT, 1.f);
+		fullbright_shader->uniform1f(LLViewerShaderMgr::TEXTURE_GAMMA, 1.f);
+
 		U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX;
 		pushBatches(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask, TRUE, TRUE);
+		pushBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, fullbright_mask, TRUE, TRUE);
+		pushBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE, fullbright_mask, TRUE, TRUE);
+		pushBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE, fullbright_mask, TRUE, TRUE);
+		pushBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE, fullbright_mask, TRUE, TRUE);
 	}
 	else
 	{
 		gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
 		U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR;
 		renderTexture(LLRenderPass::PASS_FULLBRIGHT, fullbright_mask);
+		pushBatches(LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE, fullbright_mask);
+		pushBatches(LLRenderPass::PASS_SPECMAP_EMISSIVE, fullbright_mask);
+		pushBatches(LLRenderPass::PASS_NORMMAP_EMISSIVE, fullbright_mask);
+		pushBatches(LLRenderPass::PASS_NORMSPEC_EMISSIVE, fullbright_mask);
 	}
 
 	stop_glerror();
@@ -421,3 +622,32 @@ S32 LLDrawPoolFullbright::getNumPasses()
 	return 1;
 }
 
+
+void LLDrawPoolFullbrightAlphaMask::beginPostDeferredPass(S32 pass)
+{
+	gObjectFullbrightAlphaMaskProgram.bind();
+	if (LLPipeline::sRenderingHUDs || !LLPipeline::sRenderDeferred)
+	{
+		gObjectFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 1.0f);
+	} 
+	else 
+	{
+		gObjectFullbrightAlphaMaskProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, 2.2f);
+	}
+}
+
+void LLDrawPoolFullbrightAlphaMask::renderPostDeferred(S32 pass)
+{
+	LLFastTimer t(FTM_RENDER_FULLBRIGHT);
+	LLGLDisable blend(GL_BLEND);
+	U32 fullbright_mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR | LLVertexBuffer::MAP_TEXTURE_INDEX;
+	pushMaskBatches(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, fullbright_mask, TRUE, TRUE);
+}
+
+void LLDrawPoolFullbrightAlphaMask::endPostDeferredPass(S32 pass)
+{
+	gObjectFullbrightAlphaMaskProgram.unbind();
+	LLRenderPass::endRenderPass(pass);
+}
+
+
diff --git a/indra/newview/lldrawpoolsimple.h b/indra/newview/lldrawpoolsimple.h
index bd62bc75025fc7179ea257df5760c32b8ed1cf05..608ad9e1eb0856a2095769b117f99fe070ee5cf9 100755
--- a/indra/newview/lldrawpoolsimple.h
+++ b/indra/newview/lldrawpoolsimple.h
@@ -84,6 +84,59 @@ class LLDrawPoolGrass : public LLRenderPass
 	/*virtual*/ void prerender();
 };
 
+class LLDrawPoolAlphaMask : public LLRenderPass
+{
+public:
+	enum
+	{
+		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
+							LLVertexBuffer::MAP_NORMAL |
+							LLVertexBuffer::MAP_TEXCOORD0 |
+							LLVertexBuffer::MAP_COLOR
+	};
+	virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
+
+	LLDrawPoolAlphaMask();
+
+	/*virtual*/ S32 getNumDeferredPasses() { return 1; }
+	/*virtual*/ void beginDeferredPass(S32 pass);
+	/*virtual*/ void endDeferredPass(S32 pass);
+	/*virtual*/ void renderDeferred(S32 pass);
+
+	/*virtual*/ S32	 getNumPasses() { return 1; }
+	/*virtual*/ void beginRenderPass(S32 pass);
+	/*virtual*/ void endRenderPass(S32 pass);
+	/*virtual*/ void render(S32 pass = 0);
+	/*virtual*/ void prerender();
+
+};
+
+class LLDrawPoolFullbrightAlphaMask : public LLRenderPass
+{
+public:
+	enum
+	{
+		VERTEX_DATA_MASK =	LLVertexBuffer::MAP_VERTEX |
+							LLVertexBuffer::MAP_TEXCOORD0 |
+							LLVertexBuffer::MAP_COLOR
+	};
+	virtual U32 getVertexDataMask() { return VERTEX_DATA_MASK; }
+
+	LLDrawPoolFullbrightAlphaMask();
+	
+	/*virtual*/ S32 getNumPostDeferredPasses() { return 1; }
+	/*virtual*/ void beginPostDeferredPass(S32 pass);
+	/*virtual*/ void endPostDeferredPass(S32 pass);
+	/*virtual*/ void renderPostDeferred(S32 pass);
+
+	/*virtual*/ S32	 getNumPasses() { return 1; }
+	/*virtual*/ void beginRenderPass(S32 pass);
+	/*virtual*/ void endRenderPass(S32 pass);
+	/*virtual*/ void render(S32 pass = 0);
+	/*virtual*/ void prerender();
+};
+
+
 class LLDrawPoolFullbright : public LLRenderPass
 {
 public:
diff --git a/indra/newview/lleventpoll.cpp b/indra/newview/lleventpoll.cpp
index e0f7223a8ce745949d1ee8c60df93da53f322f74..c1630318e8dcd45c06d86d4053c1e0ab8a5d2909 100755
--- a/indra/newview/lleventpoll.cpp
+++ b/indra/newview/lleventpoll.cpp
@@ -213,7 +213,7 @@ namespace
 		{
 			llwarns << "LLEventPollResponder error <" << mCount 
 					<< "> [status:" << status << "]: " << content
-					<< (mDone ? " -- done" : "") << llendl;
+					<<	(mDone ? " -- done"	: "") << llendl;
 			stop();
 
 			// At this point we have given up and the viewer will not receive HTTP messages from the simulator.
diff --git a/indra/newview/llface.cpp b/indra/newview/llface.cpp
index 281f852b0aa26cd885cc2e980ae4958418205690..f021f4ed0f4e9f11912d317806c0e6431e957a96 100755
--- a/indra/newview/llface.cpp
+++ b/indra/newview/llface.cpp
@@ -51,7 +51,7 @@
 #include "llviewerregion.h"
 #include "llviewerwindow.h"
 #include "llviewershadermgr.h"
-
+#include "llviewertexture.h"
 
 #define LL_MAX_INDICES_COUNT 1000000
 
@@ -106,41 +106,6 @@ void planarProjection(LLVector2 &tc, const LLVector4a& normal,
 	tc.mV[0] = 1.0f+((binormal.dot3(vec).getF32())*2 - 0.5f);
 }
 
-void sphericalProjection(LLVector2 &tc, const LLVector4a& normal,
-						 const LLVector4a &mCenter, const LLVector4a& vec)
-{	//BROKEN
-	/*tc.mV[0] = acosf(vd.mNormal * LLVector3(1,0,0))/3.14159f;
-	
-	tc.mV[1] = acosf(vd.mNormal * LLVector3(0,0,1))/6.284f;
-	if (vd.mNormal.mV[1] > 0)
-	{
-		tc.mV[1] = 1.0f-tc.mV[1];
-	}*/
-}
-
-void cylindricalProjection(LLVector2 &tc, const LLVector4a& normal, const LLVector4a &mCenter, const LLVector4a& vec)
-{	//BROKEN
-	/*LLVector3 binormal;
-	float d = vd.mNormal * LLVector3(1,0,0);
-	if (d >= 0.5f || d <= -0.5f)
-	{
-		binormal = LLVector3(0,1,0);
-	}
-	else{
-		binormal = LLVector3(1,0,0);
-	}
-	LLVector3 tangent = binormal % vd.mNormal;
-
-	tc.mV[1] = -((tangent*vec)*2 - 0.5f);
-
-	tc.mV[0] = acosf(vd.mNormal * LLVector3(1,0,0))/6.284f;
-
-	if (vd.mNormal.mV[1] < 0)
-	{
-		tc.mV[0] = 1.0f-tc.mV[0];
-	}*/
-}
-
 ////////////////////
 //
 // LLFace implementation
@@ -167,8 +132,12 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
 	//special value to indicate uninitialized position
 	mIndicesIndex	= 0xFFFFFFFF;
 	
-	mIndexInTex = 0;
-	mTexture		= NULL;
+	for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i)
+	{
+		mIndexInTex[i] = 0;
+		mTexture[i] = NULL;
+	}
+
 	mTEOffset		= -1;
 	mTextureIndex = 255;
 
@@ -185,8 +154,6 @@ void LLFace::init(LLDrawable* drawablep, LLViewerObject* objp)
 	mImportanceToCamera = 0.f ;
 	mBoundingSphereRadius = 0.0f ;
 
-	mAtlasInfop = NULL ;
-	mUsingAtlas  = FALSE ;
 	mHasMedia = FALSE ;
 }
 
@@ -197,9 +164,12 @@ void LLFace::destroy()
 		gPipeline.checkReferences(this);
 	}
 
-	if(mTexture.notNull())
+	for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i)
 	{
-		mTexture->removeFace(this) ;
+		if(mTexture[i].notNull())
+		{
+			mTexture[i]->removeFace(i, this) ;
+		}
 	}
 	
 	if (isState(LLFace::PARTICLE))
@@ -239,8 +209,7 @@ void LLFace::destroy()
 	}
 	
 	setDrawInfo(NULL);
-	removeAtlas();
-		
+			
 	mDrawablep = NULL;
 	mVObjp = NULL;
 }
@@ -293,48 +262,76 @@ void LLFace::setPool(LLFacePool* new_pool, LLViewerTexture *texturep)
 	setTexture(texturep) ;
 }
 
-void LLFace::setTexture(LLViewerTexture* tex) 
+void LLFace::setTexture(U32 ch, LLViewerTexture* tex) 
 {
-	if(mTexture == tex)
+	llassert(ch < LLRender::NUM_TEXTURE_CHANNELS);
+
+	if(mTexture[ch] == tex)
 	{
 		return ;
 	}
 
-	if(mTexture.notNull())
+	if(mTexture[ch].notNull())
 	{
-		mTexture->removeFace(this) ;
-		removeAtlas() ;
+		mTexture[ch]->removeFace(ch, this) ;
 	}	
 	
 	if(tex)
 	{
-		tex->addFace(this) ;
+		tex->addFace(ch, this) ;
 	}
 
-	mTexture = tex ;
+	mTexture[ch] = tex ;
+}
+
+void LLFace::setTexture(LLViewerTexture* tex) 
+{
+	setDiffuseMap(tex);
+}
+
+void LLFace::setDiffuseMap(LLViewerTexture* tex)
+{
+	setTexture(LLRender::DIFFUSE_MAP, tex);
+}
+
+void LLFace::setNormalMap(LLViewerTexture* tex)
+{
+	setTexture(LLRender::NORMAL_MAP, tex);
+}
+
+void LLFace::setSpecularMap(LLViewerTexture* tex)
+{
+	setTexture(LLRender::SPECULAR_MAP, tex);
 }
 
 void LLFace::dirtyTexture()
 {
 	LLDrawable* drawablep = getDrawable();
 
-	if (mVObjp.notNull() && mVObjp->getVolume() && 
-		mTexture.notNull() && mTexture->getComponents() == 4)
-	{ //dirty texture on an alpha object should be treated as an LoD update
-		LLVOVolume* vobj = drawablep->getVOVolume();
-		if (vobj)
+	if (mVObjp.notNull() && mVObjp->getVolume())
+	{
+		for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch)
 		{
-			vobj->mLODChanged = TRUE;
+			if (mTexture[ch].notNull() && mTexture[ch]->getComponents() == 4)
+			{ //dirty texture on an alpha object should be treated as an LoD update
+				LLVOVolume* vobj = drawablep->getVOVolume();
+				if (vobj)
+				{
+					vobj->mLODChanged = TRUE;
+				}
+				gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_VOLUME, FALSE);
+			}
 		}
-		gPipeline.markRebuild(drawablep, LLDrawable::REBUILD_VOLUME, FALSE);
-	}		
+	}
 			
 	gPipeline.markTextured(drawablep);
 }
 
-void LLFace::switchTexture(LLViewerTexture* new_texture)
+void LLFace::switchTexture(U32 ch, LLViewerTexture* new_texture)
 {
-	if(mTexture == new_texture)
+	llassert(ch < LLRender::NUM_TEXTURE_CHANNELS);
+	
+	if(mTexture[ch] == new_texture)
 	{
 		return ;
 	}
@@ -344,10 +341,17 @@ void LLFace::switchTexture(LLViewerTexture* new_texture)
 		llerrs << "Can not switch to a null texture." << llendl;
 		return;
 	}
-	new_texture->addTextureStats(mTexture->getMaxVirtualSize()) ;
 
-	getViewerObject()->changeTEImage(mTEOffset, new_texture) ;
-	setTexture(new_texture) ;	
+	llassert(mTexture[ch].notNull());
+
+	new_texture->addTextureStats(mTexture[ch]->getMaxVirtualSize()) ;
+
+	if (ch == LLRender::DIFFUSE_MAP)
+	{
+		getViewerObject()->changeTEImage(mTEOffset, new_texture) ;
+	}
+
+	setTexture(ch, new_texture) ;	
 	dirtyTexture();
 }
 
@@ -543,7 +547,9 @@ void LLFace::renderSelected(LLViewerTexture *imagep, const LLColor4& color)
 		}
 		else
 		{
-			mVertexBuffer->setBuffer(LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0);
+			// cheaters sometimes prosper...
+			//
+			mVertexBuffer->setBuffer(mVertexBuffer->getTypeMask());
 			mVertexBuffer->draw(LLRender::TRIANGLES, mIndicesCount, mIndicesIndex);
 		}
 
@@ -811,6 +817,12 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
 			size.mul(scale);
 		}
 
+		// Catch potential badness from normalization before it happens
+		//
+		llassert(mat_normal.mMatrix[0].isFinite3() && (mat_normal.mMatrix[0].dot3(mat_normal.mMatrix[0]).getF32() > F_APPROXIMATELY_ZERO));
+		llassert(mat_normal.mMatrix[1].isFinite3() && (mat_normal.mMatrix[1].dot3(mat_normal.mMatrix[1]).getF32() > F_APPROXIMATELY_ZERO));
+		llassert(mat_normal.mMatrix[2].isFinite3() && (mat_normal.mMatrix[2].dot3(mat_normal.mMatrix[2]).getF32() > F_APPROXIMATELY_ZERO));
+
 		mat_normal.mMatrix[0].normalize3fast();
 		mat_normal.mMatrix[1].normalize3fast();
 		mat_normal.mMatrix[2].normalize3fast();
@@ -896,7 +908,7 @@ BOOL LLFace::genVolumeBBoxes(const LLVolume &volume, S32 f,
 // integrated with getGeometryVolume() for its texture coordinate
 // generation - but i'll leave that to someone more familiar
 // with the implications.
-LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, LLVector3 position, LLVector3 normal)
+LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, const LLVector4a& position, const LLVector4a& normal)
 {
 	LLVector2 tc = surface_coord;
 	
@@ -916,7 +928,9 @@ LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, LLVector3 position,
 		LLVector4a& center = *(mDrawablep->getVOVolume()->getVolume()->getVolumeFace(mTEOffset).mCenter);
 		
 		LLVector4a volume_position;
-		volume_position.load3(mDrawablep->getVOVolume()->agentPositionToVolume(position).mV);
+		LLVector3 v_position(position.getF32ptr());
+
+		volume_position.load3(mDrawablep->getVOVolume()->agentPositionToVolume(v_position).mV);
 		
 		if (!mDrawablep->getVOVolume()->isVolumeGlobal())
 		{
@@ -926,23 +940,14 @@ LLVector2 LLFace::surfaceToTexture(LLVector2 surface_coord, LLVector3 position,
 		}
 		
 		LLVector4a volume_normal;
-		volume_normal.load3(mDrawablep->getVOVolume()->agentDirectionToVolume(normal).mV);
+		LLVector3 v_normal(normal.getF32ptr());
+		volume_normal.load3(mDrawablep->getVOVolume()->agentDirectionToVolume(v_normal).mV);
 		volume_normal.normalize3fast();
 		
-		switch (texgen)
+		if (texgen == LLTextureEntry::TEX_GEN_PLANAR)
 		{
-		case LLTextureEntry::TEX_GEN_PLANAR:
 			planarProjection(tc, volume_normal, center, volume_position);
-			break;
-		case LLTextureEntry::TEX_GEN_SPHERICAL:
-			sphericalProjection(tc, volume_normal, center, volume_position);
-			break;
-		case LLTextureEntry::TEX_GEN_CYLINDRICAL:
-			cylindricalProjection(tc, volume_normal, center, volume_position);
-			break;
-		default:
-			break;
-		}		
+		}
 	}
 
 	if (mTextureMatrix)	// if we have a texture matrix, use it
@@ -969,7 +974,12 @@ void LLFace::getPlanarProjectedParams(LLQuaternion* face_rot, LLVector3* face_po
 	const LLMatrix4& vol_mat = getWorldMatrix();
 	const LLVolumeFace& vf = getViewerObject()->getVolume()->getVolumeFace(mTEOffset);
 	const LLVector4a& normal4a = vf.mNormals[0];
-	const LLVector4a& binormal4a = vf.mBinormals[0];
+	const LLVector4a& tangent = vf.mTangents[0];
+
+	LLVector4a binormal4a;
+	binormal4a.setCross3(normal4a, tangent);
+	binormal4a.mul(tangent.getF32ptr()[3]);
+
 	LLVector2 projected_binormal;
 	planarProjection(projected_binormal, normal4a, *vf.mCenter, binormal4a);
 	projected_binormal -= LLVector2(0.5f, 0.5f); // this normally happens in xform()
@@ -1059,6 +1069,12 @@ bool LLFace::canRenderAsMask()
 		return false;
 	}
 	
+	LLMaterial* mat = te->getMaterialParams();
+	if (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND)
+	{
+		return false;
+	}
+	
 	if ((te->getColor().mV[3] == 1.0f) && // can't treat as mask if we have face alpha
 		(te->getGlow() == 0.f) && // glowing masks are hard to implement - don't mask
 		getTexture()->getIsAlphaMask()) // texture actually qualifies for masking (lazily recalculated but expensive)
@@ -1091,7 +1107,7 @@ void LLFace::cacheFaceInVRAM(const LLVolumeFace& vf)
 {
 	LLFastTimer t(FTM_FACE_GEOM_VOLUME);
 	U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 |
-				LLVertexBuffer::MAP_BINORMAL | LLVertexBuffer::MAP_NORMAL;
+				LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_NORMAL;
 	
 	if (vf.mWeights)
 	{
@@ -1104,11 +1120,11 @@ void LLFace::cacheFaceInVRAM(const LLVolumeFace& vf)
 	buff->allocateBuffer(vf.mNumVertices, 0, true);
 
 	LLStrider<LLVector4a> f_vert;
-	LLStrider<LLVector3> f_binorm;
+	LLStrider<LLVector4a> f_tangent;
 	LLStrider<LLVector3> f_norm;
 	LLStrider<LLVector2> f_tc;
 
-	buff->getBinormalStrider(f_binorm);
+	buff->getTangentStrider(f_tangent);
 	buff->getVertexStrider(f_vert);
 	buff->getNormalStrider(f_norm);
 	buff->getTexCoord0Strider(f_tc);
@@ -1116,7 +1132,7 @@ void LLFace::cacheFaceInVRAM(const LLVolumeFace& vf)
 	for (U32 i = 0; i < vf.mNumVertices; ++i)
 	{
 		*f_vert++ = vf.mPositions[i];
-		(*f_binorm++).set(vf.mBinormals[i].getF32ptr());
+		*f_tangent++ = vf.mTangents[i];
 		*f_tc++ = vf.mTexCoords[i];
 		(*f_norm++).set(vf.mNormals[i].getF32ptr());
 	}
@@ -1158,7 +1174,7 @@ static LLFastTimer::DeclareTimer FTM_FACE_GEOM_TEXTURE("Texture");
 static LLFastTimer::DeclareTimer FTM_FACE_GEOM_COLOR("Color");
 static LLFastTimer::DeclareTimer FTM_FACE_GEOM_EMISSIVE("Emissive");
 static LLFastTimer::DeclareTimer FTM_FACE_GEOM_WEIGHTS("Weights");
-static LLFastTimer::DeclareTimer FTM_FACE_GEOM_BINORMAL("Binormal");
+static LLFastTimer::DeclareTimer FTM_FACE_GEOM_TANGENT("Binormal");
 static LLFastTimer::DeclareTimer FTM_FACE_GEOM_INDEX("Index");
 static LLFastTimer::DeclareTimer FTM_FACE_GEOM_INDEX_TAIL("Tail");
 static LLFastTimer::DeclareTimer FTM_FACE_POSITION_STORE("Pos");
@@ -1219,11 +1235,12 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	}
 
 	LLStrider<LLVector3> vert;
-	LLStrider<LLVector2> tex_coords;
+	LLStrider<LLVector2> tex_coords0;
+	LLStrider<LLVector2> tex_coords1;
 	LLStrider<LLVector2> tex_coords2;
 	LLStrider<LLVector3> norm;
 	LLStrider<LLColor4U> colors;
-	LLStrider<LLVector3> binorm;
+	LLStrider<LLVector3> tangent;
 	LLStrider<U16> indicesp;
 	LLStrider<LLVector4> wght;
 
@@ -1245,33 +1262,12 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	bool rebuild_emissive = rebuild_color && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_EMISSIVE);
 	bool rebuild_tcoord = full_rebuild || mDrawablep->isState(LLDrawable::REBUILD_TCOORD);
 	bool rebuild_normal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_NORMAL);
-	bool rebuild_binormal = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_BINORMAL);
+	bool rebuild_tangent = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TANGENT);
 	bool rebuild_weights = rebuild_pos && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_WEIGHT4);
 
 	const LLTextureEntry *tep = mVObjp->getTE(f);
 	const U8 bump_code = tep ? tep->getBumpmap() : 0;
 
-	F32 tcoord_xoffset = 0.f ;
-	F32 tcoord_yoffset = 0.f ;
-	F32 tcoord_xscale = 1.f ;
-	F32 tcoord_yscale = 1.f ;
-	BOOL in_atlas = FALSE ;
-
-	if (rebuild_tcoord)
-	{
-		in_atlas = isAtlasInUse() ;
-		if(in_atlas)
-		{
-			const LLVector2* tmp = getTexCoordOffset() ;
-			tcoord_xoffset = tmp->mV[0] ; 
-			tcoord_yoffset = tmp->mV[1] ;
-
-			tmp = getTexCoordScale() ;
-			tcoord_xscale = tmp->mV[0] ; 
-			tcoord_yscale = tmp->mV[1] ;	
-		}
-	}
-	
 	BOOL is_static = mDrawablep->isStatic();
 	BOOL is_global = is_static;
 
@@ -1289,19 +1285,41 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 	LLColor4U color = tep->getColor();
 
 	if (rebuild_color)
-	{
-		if (tep)
+	{ //decide if shiny goes in alpha channel of color
+		if (tep && 
+			getPoolType() != LLDrawPool::POOL_ALPHA)  // <--- alpha channel MUST contain transparency, not shiny
 		{
-			GLfloat alpha[4] =
-			{
-				0.00f,
-				0.25f,
-				0.5f,
-				0.75f
-			};
+			LLMaterial* mat = tep->getMaterialParams().get();
+						
+			bool shiny_in_alpha = false;
 			
-			if (getPoolType() != LLDrawPool::POOL_ALPHA && (LLPipeline::sRenderDeferred || (LLPipeline::sRenderBump && tep->getShiny())))
+			if (LLPipeline::sRenderDeferred)
+			{ //store shiny in alpha if we don't have a specular map
+				if  (!mat || mat->getSpecularID().isNull())
+				{
+					shiny_in_alpha = true;
+				}
+			}
+			else
 			{
+				if (!mat || mat->getDiffuseAlphaMode() != LLMaterial::DIFFUSE_ALPHA_MODE_MASK)
+				{
+					shiny_in_alpha = true;
+				}
+			}
+
+			if (shiny_in_alpha)
+			{
+
+				GLfloat alpha[4] =
+				{
+					0.00f,
+					0.25f,
+					0.5f,
+					0.75f
+				};
+			
+				llassert(tep->getShiny() <= 3);
 				color.mV[3] = U8 (alpha[tep->getShiny()] * 255);
 			}
 		}
@@ -1392,7 +1410,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 		if (vf.mVertexBuffer.isNull() || buff->getNumVerts() != vf.mNumVertices)
 		{
-			mVObjp->getVolume()->genBinormals(f);
+			mVObjp->getVolume()->genTangents(f);
 			LLFace::cacheFaceInVRAM(vf);
 			buff = (LLVertexBuffer*) vf.mVertexBuffer.get();
 		}		
@@ -1477,15 +1495,15 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			glEndTransformFeedback();
 		}
 
-		if (rebuild_binormal)
+		if (rebuild_tangent)
 		{
-			LLFastTimer t(FTM_FACE_GEOM_BINORMAL);
-			gTransformBinormalProgram.bind();
+			LLFastTimer t(FTM_FACE_GEOM_TANGENT);
+			gTransformTangentProgram.bind();
 			
-			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_BINORMAL, mGeomIndex, mGeomCount);
+			mVertexBuffer->bindForFeedback(0, LLVertexBuffer::TYPE_TANGENT, mGeomIndex, mGeomCount);
 						
 			glBeginTransformFeedback(GL_POINTS);
-			buff->setBuffer(LLVertexBuffer::MAP_BINORMAL);
+			buff->setBuffer(LLVertexBuffer::MAP_TANGENT);
 			push_for_transform(buff, vf.mNumVertices, mGeomCount);
 			glEndTransformFeedback();
 		}
@@ -1547,7 +1565,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 		
 			if (bump_code)
 			{
-				mVObjp->getVolume()->genBinormals(f);
+				mVObjp->getVolume()->genTangents(f);
 				F32 offset_multiple; 
 				switch( bump_code )
 				{
@@ -1556,11 +1574,11 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 					break;
 					case BE_BRIGHTNESS:
 					case BE_DARKNESS:
-					if( mTexture.notNull() && mTexture->hasGLTexture())
+					if( mTexture[LLRender::DIFFUSE_MAP].notNull() && mTexture[LLRender::DIFFUSE_MAP]->hasGLTexture())
 					{
 						// Offset by approximately one texel
-						S32 cur_discard = mTexture->getDiscardLevel();
-						S32 max_size = llmax( mTexture->getWidth(), mTexture->getHeight() );
+						S32 cur_discard = mTexture[LLRender::DIFFUSE_MAP]->getDiscardLevel();
+						S32 max_size = llmax( mTexture[LLRender::DIFFUSE_MAP]->getWidth(), mTexture[LLRender::DIFFUSE_MAP]->getHeight() );
 						max_size <<= cur_discard;
 						const F32 ARTIFICIAL_OFFSET = 2.f;
 						offset_multiple = ARTIFICIAL_OFFSET / (F32)max_size;
@@ -1596,16 +1614,23 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			U8 texgen = getTextureEntry()->getTexGen();
 			if (rebuild_tcoord && texgen != LLTextureEntry::TEX_GEN_DEFAULT)
 			{ //planar texgen needs binormals
-				mVObjp->getVolume()->genBinormals(f);
+				mVObjp->getVolume()->genTangents(f);
 			}
 
 			U8 tex_mode = 0;
 	
+			bool tex_anim = false;
+
+			LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp;	
+			tex_mode = vobj->mTexAnimMode;
+
+			if (vobj->mTextureAnimp)
+			{ //texture animation is in play, override specular and normal map tex coords with diffuse texcoords
+				tex_anim = true;
+			}
+
 			if (isState(TEXTURE_ANIM))
 			{
-				LLVOVolume* vobj = (LLVOVolume*) (LLViewerObject*) mVObjp;	
-				tex_mode = vobj->mTexAnimMode;
-
 				if (!tex_mode)
 				{
 					clearState(TEXTURE_ANIM);
@@ -1620,7 +1645,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 
 					do_xform = false;
 				}
-
+				
 				if (getVirtualSize() >= MIN_TEX_ANIM_SIZE)
 				{ //don't override texture transform during tc bake
 					tex_mode = 0;
@@ -1630,12 +1655,21 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			LLVector4a scalea;
 			scalea.load3(scale.mV);
 
+			LLMaterial* mat = tep->getMaterialParams().get();
+
 			bool do_bump = bump_code && mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1);
-			bool do_tex_mat = tex_mode && mTextureMatrix;
 
-			if (!in_atlas && !do_bump)
-			{ //not in atlas or not bump mapped, might be able to do a cheap update
-				mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount);
+			if (mat && !do_bump)
+			{
+				do_bump  = mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1)
+					     || mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD2);
+			}
+			
+			bool do_tex_mat = tex_mode && mTextureMatrix;
+						
+			if (!do_bump)
+			{ //not bump mapped, might be able to do a cheap update
+				mVertexBuffer->getTexCoord0Strider(tex_coords0, mGeomIndex, mGeomCount);
 
 				if (texgen != LLTextureEntry::TEX_GEN_PLANAR)
 				{
@@ -1646,12 +1680,12 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 						{
 							LLFastTimer t(FTM_FACE_TEX_QUICK_NO_XFORM);
 							S32 tc_size = (num_vertices*2*sizeof(F32)+0xF) & ~0xF;
-							LLVector4a::memcpyNonAliased16((F32*) tex_coords.get(), (F32*) vf.mTexCoords, tc_size);
+							LLVector4a::memcpyNonAliased16((F32*) tex_coords0.get(), (F32*) vf.mTexCoords, tc_size);
 						}
 						else
 						{
 							LLFastTimer t(FTM_FACE_TEX_QUICK_XFORM);
-							F32* dst = (F32*) tex_coords.get();
+							F32* dst = (F32*) tex_coords0.get();
 							LLVector4a* src = (LLVector4a*) vf.mTexCoords;
 
 							LLVector4a trans;
@@ -1686,7 +1720,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 						}
 					}
 					else
-					{ //do tex mat, no texgen, no atlas, no bump
+					{ //do tex mat, no texgen, no bump
 						for (S32 i = 0; i < num_vertices; i++)
 						{	
 							LLVector2 tc(vf.mTexCoords[i]);
@@ -1697,12 +1731,12 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 							tmp = tmp * *mTextureMatrix;
 							tc.mV[0] = tmp.mV[0];
 							tc.mV[1] = tmp.mV[1];
-							*tex_coords++ = tc;	
+							*tex_coords0++ = tc;	
 						}
 					}
 				}
 				else
-				{ //no bump, no atlas, tex gen planar
+				{ //no bump, tex gen planar
 					LLFastTimer t(FTM_FACE_TEX_QUICK_PLANAR);
 					if (do_tex_mat)
 					{
@@ -1720,7 +1754,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 							tc.mV[0] = tmp.mV[0];
 							tc.mV[1] = tmp.mV[1];
 				
-							*tex_coords++ = tc;	
+							*tex_coords0++ = tc;	
 						}
 					}
 					else
@@ -1736,7 +1770,7 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 						
 							xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
 
-							*tex_coords++ = tc;	
+							*tex_coords0++ = tc;	
 						}
 					}
 				}
@@ -1747,145 +1781,104 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 				}
 			}
 			else
-			{ //either bump mapped or in atlas, just do the whole expensive loop
+			{ //bump mapped or has material, just do the whole expensive loop
 				LLFastTimer t(FTM_FACE_TEX_DEFAULT);
-				mVertexBuffer->getTexCoord0Strider(tex_coords, mGeomIndex, mGeomCount, map_range);
-
-				std::vector<LLVector2> bump_tc;
-		
-				for (S32 i = 0; i < num_vertices; i++)
-				{	
-					LLVector2 tc(vf.mTexCoords[i]);
-			
-					LLVector4a& norm = vf.mNormals[i];
-				
-					LLVector4a& center = *(vf.mCenter);
-		   
-					if (texgen != LLTextureEntry::TEX_GEN_DEFAULT)
-					{
-						LLVector4a vec = vf.mPositions[i];
 				
-						vec.mul(scalea);
+				std::vector<LLVector2> bump_tc;
 
-						switch (texgen)
-						{
-							case LLTextureEntry::TEX_GEN_PLANAR:
-								planarProjection(tc, norm, center, vec);
-								break;
-							case LLTextureEntry::TEX_GEN_SPHERICAL:
-								sphericalProjection(tc, norm, center, vec);
-								break;
-							case LLTextureEntry::TEX_GEN_CYLINDRICAL:
-								cylindricalProjection(tc, norm, center, vec);
-								break;
-							default:
-								break;
-						}		
-					}
+				if (mat && !mat->getNormalID().isNull())
+				{ //writing out normal and specular texture coordinates, not bump offsets
+					do_bump = false;
+				}
 
-					if (tex_mode && mTextureMatrix)
-					{
-						LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f);
-						tmp = tmp * *mTextureMatrix;
-						tc.mV[0] = tmp.mV[0];
-						tc.mV[1] = tmp.mV[1];
-					}
-					else
-					{
-						xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
-					}
+				LLStrider<LLVector2> dst;
 
-					if(in_atlas)
+				for (U32 ch = 0; ch < 3; ++ch)
+				{
+					switch (ch)
 					{
-						//
-						//manually calculate tex-coord per vertex for varying address modes.
-						//should be removed if shader can handle this.
-						//
-
-						S32 int_part = 0 ;
-						switch(mTexture->getAddressMode())
-						{
-						case LLTexUnit::TAM_CLAMP:
-							if(tc.mV[0] < 0.f)
-							{
-								tc.mV[0] = 0.f ;
-							}
-							else if(tc.mV[0] > 1.f)
-							{
-								tc.mV[0] = 1.f;
-							}
-
-							if(tc.mV[1] < 0.f)
-							{
-								tc.mV[1] = 0.f ;
-							}
-							else if(tc.mV[1] > 1.f)
-							{
-								tc.mV[1] = 1.f;
-							}
+						case 0: 
+							mVertexBuffer->getTexCoord0Strider(dst, mGeomIndex, mGeomCount, map_range); 
 							break;
-						case LLTexUnit::TAM_MIRROR:
-							if(tc.mV[0] < 0.f)
-							{
-								tc.mV[0] = -tc.mV[0] ;
-							}
-							int_part = (S32)tc.mV[0] ;
-							if(int_part & 1) //odd number
-							{
-								tc.mV[0] = int_part + 1 - tc.mV[0] ;
-							}
-							else //even number
+						case 1:
+							if (mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD1))
 							{
-								tc.mV[0] -= int_part ;
-							}
+								mVertexBuffer->getTexCoord1Strider(dst, mGeomIndex, mGeomCount, map_range);
+								if (mat && !tex_anim)
+								{
+									r  = mat->getNormalRotation();
+									mat->getNormalOffset(os, ot);
+									mat->getNormalRepeat(ms, mt);
 
-							if(tc.mV[1] < 0.f)
-							{
-								tc.mV[1] = -tc.mV[1] ;
-							}
-							int_part = (S32)tc.mV[1] ;
-							if(int_part & 1) //odd number
-							{
-								tc.mV[1] = int_part + 1 - tc.mV[1] ;
+									cos_ang = cos(r);
+									sin_ang = sin(r);
+
+								}
 							}
-							else //even number
+							else
 							{
-								tc.mV[1] -= int_part ;
+								continue;
 							}
 							break;
-						case LLTexUnit::TAM_WRAP:
-							if(tc.mV[0] > 1.f)
-								tc.mV[0] -= (S32)(tc.mV[0] - 0.00001f) ;
-							else if(tc.mV[0] < -1.f)
-								tc.mV[0] -= (S32)(tc.mV[0] + 0.00001f) ;
-
-							if(tc.mV[1] > 1.f)
-								tc.mV[1] -= (S32)(tc.mV[1] - 0.00001f) ;
-							else if(tc.mV[1] < -1.f)
-								tc.mV[1] -= (S32)(tc.mV[1] + 0.00001f) ;
-
-							if(tc.mV[0] < 0.f)
+						case 2:
+							if (mVertexBuffer->hasDataType(LLVertexBuffer::TYPE_TEXCOORD2))
 							{
-								tc.mV[0] = 1.0f + tc.mV[0] ;
+								mVertexBuffer->getTexCoord2Strider(dst, mGeomIndex, mGeomCount, map_range);
+								if (mat && !tex_anim)
+								{
+									r  = mat->getSpecularRotation();
+									mat->getSpecularOffset(os, ot);
+									mat->getSpecularRepeat(ms, mt);
+
+									cos_ang = cos(r);
+									sin_ang = sin(r);
+								}
 							}
-							if(tc.mV[1] < 0.f)
+							else
 							{
-								tc.mV[1] = 1.0f + tc.mV[1] ;
+								continue;
 							}
 							break;
-						default:
-							break;
-						}
-				
-						tc.mV[0] = tcoord_xoffset + tcoord_xscale * tc.mV[0] ;
-						tc.mV[1] = tcoord_yoffset + tcoord_yscale * tc.mV[1] ;
 					}
+					
+
+					for (S32 i = 0; i < num_vertices; i++)
+					{	
+						LLVector2 tc(vf.mTexCoords[i]);
+			
+						LLVector4a& norm = vf.mNormals[i];
+				
+						LLVector4a& center = *(vf.mCenter);
+		   
+						if (texgen != LLTextureEntry::TEX_GEN_DEFAULT)
+						{
+							LLVector4a vec = vf.mPositions[i];
 				
+							vec.mul(scalea);
 
-					*tex_coords++ = tc;
-					if (do_bump)
-					{
-						bump_tc.push_back(tc);
+							if (texgen == LLTextureEntry::TEX_GEN_PLANAR)
+							{
+								planarProjection(tc, norm, center, vec);
+							}
+						}
+
+						if (tex_mode && mTextureMatrix)
+						{
+							LLVector3 tmp(tc.mV[0], tc.mV[1], 0.f);
+							tmp = tmp * *mTextureMatrix;
+							tc.mV[0] = tmp.mV[0];
+							tc.mV[1] = tmp.mV[1];
+						}
+						else
+						{
+							xform(tc, cos_ang, sin_ang, os, ot, ms, mt);
+						}
+
+						*dst++ = tc;
+						if (do_bump)
+						{
+							bump_tc.push_back(tc);
+						}
 					}
 				}
 
@@ -1894,17 +1887,20 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 					mVertexBuffer->flush();
 				}
 
-				if (do_bump)
+				if (!mat && do_bump)
 				{
-					mVertexBuffer->getTexCoord1Strider(tex_coords2, mGeomIndex, mGeomCount, map_range);
+					mVertexBuffer->getTexCoord1Strider(tex_coords1, mGeomIndex, mGeomCount, map_range);
 		
 					for (S32 i = 0; i < num_vertices; i++)
 					{
-						LLVector4a tangent;
-						tangent.setCross3(vf.mBinormals[i], vf.mNormals[i]);
+						LLVector4a tangent = vf.mTangents[i];
 
+						LLVector4a binorm;
+						binorm.setCross3(vf.mNormals[i], tangent);
+						binorm.mul(tangent.getF32ptr()[3]);
+						
 						LLMatrix4a tangent_to_object;
-						tangent_to_object.setRows(tangent, vf.mBinormals[i], vf.mNormals[i]);
+						tangent_to_object.setRows(tangent, binorm, vf.mNormals[i]);
 						LLVector4a t;
 						tangent_to_object.rotate(binormal_dir, t);
 						LLVector4a binormal;
@@ -1920,10 +1916,11 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 						}
 
 						binormal.normalize3fast();
+
 						LLVector2 tc = bump_tc[i];
 						tc += LLVector2( bump_s_primary_light_ray.dot3(tangent).getF32(), bump_t_primary_light_ray.dot3(binormal).getF32() );
 					
-						*tex_coords2++ = tc;
+						*tex_coords1++ = tc;
 					}
 
 					if (map_range)
@@ -2006,7 +2003,6 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			LLFastTimer t(FTM_FACE_GEOM_NORMAL);
 			mVertexBuffer->getNormalStrider(norm, mGeomIndex, mGeomCount, map_range);
 			F32* normals = (F32*) norm.get();
-	
 			for (S32 i = 0; i < num_vertices; i++)
 			{	
 				LLVector4a normal;
@@ -2022,19 +2018,27 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			}
 		}
 		
-		if (rebuild_binormal)
+		if (rebuild_tangent)
 		{
-			LLFastTimer t(FTM_FACE_GEOM_BINORMAL);
-			mVertexBuffer->getBinormalStrider(binorm, mGeomIndex, mGeomCount, map_range);
-			F32* binormals = (F32*) binorm.get();
-		
+			LLFastTimer t(FTM_FACE_GEOM_TANGENT);
+			mVertexBuffer->getTangentStrider(tangent, mGeomIndex, mGeomCount, map_range);
+			F32* tangents = (F32*) tangent.get();
+			
+			mVObjp->getVolume()->genTangents(f);
+			
+			LLVector4Logical mask;
+			mask.clear();
+			mask.setElement<3>();
+
 			for (S32 i = 0; i < num_vertices; i++)
-			{	
-				LLVector4a binormal;
-				mat_normal.rotate(vf.mBinormals[i], binormal);
-				binormal.normalize3fast();
-				binormal.store4a(binormals);
-				binormals += 4;
+			{
+				LLVector4a tangent_out;
+				mat_normal.rotate(vf.mTangents[i], tangent_out);
+				tangent_out.normalize3fast();
+				tangent_out.setSelectWithMask(mask, vf.mTangents[i], tangent_out);
+				tangent_out.store4a(tangents);
+				
+				tangents += 4;
 			}
 
 			if (map_range)
@@ -2097,11 +2101,10 @@ BOOL LLFace::getGeometryVolume(const LLVolume& volume,
 			LLVector4a src;
 
 		
-			U32 glow32 = glow |
-						 (glow << 8) |
-						 (glow << 16) |
-						 (glow << 24);
+			LLColor4U glow4u = LLColor4U(0,0,0,glow);
 
+			U32 glow32 = glow4u.mAll;
+			
 			U32 vec[4];
 			vec[0] = vec[1] = vec[2] = vec[3] = glow32;
 		
@@ -2153,9 +2156,9 @@ BOOL LLFace::hasMedia() const
 	{
 		return TRUE ;
 	}
-	if(mTexture.notNull()) 
+	if(mTexture[LLRender::DIFFUSE_MAP].notNull()) 
 	{
-		return mTexture->hasParcelMedia() ;  //if has a parcel media
+		return mTexture[LLRender::DIFFUSE_MAP]->hasParcelMedia() ;  //if has a parcel media
 	}
 
 	return FALSE ; //no media.
@@ -2207,7 +2210,7 @@ F32 LLFace::getTextureVirtualSize()
 	face_area = LLFace::adjustPixelArea(mImportanceToCamera, face_area) ;
 	if(face_area > LLViewerTexture::sMinLargeImageSize) //if is large image, shrink face_area by considering the partial overlapping.
 	{
-		if(mImportanceToCamera > LEAST_IMPORTANCE_FOR_LARGE_IMAGE && mTexture.notNull() && mTexture->isLargeImage())
+		if(mImportanceToCamera > LEAST_IMPORTANCE_FOR_LARGE_IMAGE && mTexture[LLRender::DIFFUSE_MAP].notNull() && mTexture[LLRender::DIFFUSE_MAP]->isLargeImage())
 		{		
 			face_area *= adjustPartialOverlapPixelArea(cos_angle_to_view_dir, radius );
 		}	
@@ -2246,7 +2249,7 @@ BOOL LLFace::calcPixelArea(F32& cos_angle_to_view_dir, F32& radius)
 		dist *= 16.f;
 	}
 
-	lookAt.normalize3fast() ;	
+	lookAt.normalize3fast();	
 
 	//get area of circle around node
 	F32 app_angle = atanf((F32) sqrt(size_squared) / dist);
@@ -2574,159 +2577,13 @@ LLVector3 LLFace::getPositionAgent() const
 	}
 }
 
-//
-//atlas
-//
-void LLFace::removeAtlas()
-{
-	setAtlasInUse(FALSE) ;
-	mAtlasInfop = NULL ;	
-}
-
-const LLTextureAtlas* LLFace::getAtlas()const 
-{
-	if(mAtlasInfop)
-	{
-		return mAtlasInfop->getAtlas() ;
-	}
-	return NULL ;
-}
-
-const LLVector2* LLFace::getTexCoordOffset()const 
-{
-	if(isAtlasInUse())
-	{
-		return mAtlasInfop->getTexCoordOffset() ;
-	}
-	return NULL ;
-}
-const LLVector2* LLFace::getTexCoordScale() const 
-{
-	if(isAtlasInUse())
-	{
-		return mAtlasInfop->getTexCoordScale() ;
-	}
-	return NULL ;
-}
-
-BOOL LLFace::isAtlasInUse()const
-{
-	return mUsingAtlas ;
-}
-
-BOOL LLFace::canUseAtlas()const
+LLViewerTexture* LLFace::getTexture(U32 ch) const
 {
-	//no drawable or no spatial group, do not use atlas
-	if(!mDrawablep || !mDrawablep->getSpatialGroup())
-	{
-		return FALSE ;
-	}
-
-	//if bump face, do not use atlas
-	if(getTextureEntry() && getTextureEntry()->getBumpmap())
-	{
-		return FALSE ;
-	}
-
-	//if animated texture, do not use atlas
-	if(isState(TEXTURE_ANIM))
-	{
-		return FALSE ;
-	}
+	llassert(ch < LLRender::NUM_TEXTURE_CHANNELS);
 
-	return TRUE ;
-}
-
-void LLFace::setAtlasInUse(BOOL flag)
-{
-	//no valid atlas to use.
-	if(flag && (!mAtlasInfop || !mAtlasInfop->isValid()))
-	{
-		flag = FALSE ;
-	}
-
-	if(!flag && !mUsingAtlas)
-	{
-		return ;
-	}
-
-	//
-	//at this stage (flag || mUsingAtlas) is always true.
-	//
-
-	//rebuild the tex coords
-	if(mDrawablep)
-	{
-		gPipeline.markRebuild(mDrawablep, LLDrawable::REBUILD_TCOORD);
-		mUsingAtlas = flag ;
-	}
-	else
-	{
-		mUsingAtlas = FALSE ;
-	}
+	return mTexture[ch] ;
 }
 
-LLTextureAtlasSlot* LLFace::getAtlasInfo()
-{
-	return mAtlasInfop ;
-}
-
-void LLFace::setAtlasInfo(LLTextureAtlasSlot* atlasp)
-{	
-	if(mAtlasInfop != atlasp)
-	{
-		if(mAtlasInfop)
-		{
-			//llerrs << "Atlas slot changed!" << llendl ;
-		}
-		mAtlasInfop = atlasp ;
-	}
-}
-
-LLViewerTexture* LLFace::getTexture() const
-{
-	if(isAtlasInUse())
-	{
-		return (LLViewerTexture*)mAtlasInfop->getAtlas() ;
-	}
-
-	return mTexture ;
-}
-
-//switch to atlas or switch back to gl texture 
-//return TRUE if using atlas.
-BOOL LLFace::switchTexture()
-{
-	//no valid atlas or texture
-	if(!mAtlasInfop || !mAtlasInfop->isValid() || !mTexture)
-	{
-		return FALSE ;
-	}
-	
-	if(mTexture->getTexelsInAtlas() >= (U32)mVSize || 
-		mTexture->getTexelsInAtlas() >= mTexture->getTexelsInGLTexture())
-	{
-		//switch to use atlas
-		//atlas resolution is qualified, use it.		
-		if(!mUsingAtlas)
-		{
-			setAtlasInUse(TRUE) ;
-		}
-	}
-	else //if atlas not qualified.
-	{
-		//switch back to GL texture
-		if(mUsingAtlas && mTexture->isGLTextureCreated() && 
-			mTexture->getDiscardLevel() < mTexture->getDiscardLevelInAtlas())
-		{
-			setAtlasInUse(FALSE) ;
-		}
-	}
-
-	return mUsingAtlas ;
-}
-
-
 void LLFace::setVertexBuffer(LLVertexBuffer* buffer)
 {
 	mVertexBuffer = buffer;
@@ -2742,6 +2599,22 @@ void LLFace::clearVertexBuffer()
 U32 LLFace::getRiggedDataMask(U32 type)
 {
 	static const U32 rigged_data_mask[] = {
+		LLDrawPoolAvatar::RIGGED_MATERIAL_MASK,
+		LLDrawPoolAvatar::RIGGED_MATERIAL_ALPHA_VMASK,
+		LLDrawPoolAvatar::RIGGED_MATERIAL_ALPHA_MASK_MASK,
+		LLDrawPoolAvatar::RIGGED_MATERIAL_ALPHA_EMISSIVE_MASK,
+		LLDrawPoolAvatar::RIGGED_SPECMAP_VMASK,
+		LLDrawPoolAvatar::RIGGED_SPECMAP_BLEND_MASK,
+		LLDrawPoolAvatar::RIGGED_SPECMAP_MASK_MASK,
+		LLDrawPoolAvatar::RIGGED_SPECMAP_EMISSIVE_MASK,
+		LLDrawPoolAvatar::RIGGED_NORMMAP_VMASK,
+		LLDrawPoolAvatar::RIGGED_NORMMAP_BLEND_MASK,
+		LLDrawPoolAvatar::RIGGED_NORMMAP_MASK_MASK,
+		LLDrawPoolAvatar::RIGGED_NORMMAP_EMISSIVE_MASK,
+		LLDrawPoolAvatar::RIGGED_NORMSPEC_VMASK,
+		LLDrawPoolAvatar::RIGGED_NORMSPEC_BLEND_MASK,
+		LLDrawPoolAvatar::RIGGED_NORMSPEC_MASK_MASK,
+		LLDrawPoolAvatar::RIGGED_NORMSPEC_EMISSIVE_MASK,
 		LLDrawPoolAvatar::RIGGED_SIMPLE_MASK,
 		LLDrawPoolAvatar::RIGGED_FULLBRIGHT_MASK,
 		LLDrawPoolAvatar::RIGGED_SHINY_MASK,
diff --git a/indra/newview/llface.h b/indra/newview/llface.h
index de4d03351ce39ad319f01bb4ba932065e778ff10..0687544d53880f00ba956e9d6a40fa0046643cfd 100755
--- a/indra/newview/llface.h
+++ b/indra/newview/llface.h
@@ -41,7 +41,6 @@
 #include "llvertexbuffer.h"
 #include "llviewertexture.h"
 #include "lldrawable.h"
-#include "lltextureatlasmanager.h"
 
 class LLFacePool;
 class LLVolume;
@@ -50,7 +49,6 @@ class LLTextureEntry;
 class LLVertexProgram;
 class LLViewerTexture;
 class LLGeometryManager;
-class LLTextureAtlasSlot;
 
 const F32 MIN_ALPHA_SIZE = 1024.f;
 const F32 MIN_TEX_ANIM_SIZE = 512.f;
@@ -110,13 +108,17 @@ class LLFace
 	U16				getGeomStart()		const	{ return mGeomIndex; }		// index into draw pool
 	void			setTextureIndex(U8 index);
 	U8				getTextureIndex() const		{ return mTextureIndex; }
+	void			setTexture(U32 ch, LLViewerTexture* tex);
 	void			setTexture(LLViewerTexture* tex) ;
-	void            switchTexture(LLViewerTexture* new_texture);
+	void			setDiffuseMap(LLViewerTexture* tex);
+	void			setNormalMap(LLViewerTexture* tex);
+	void			setSpecularMap(LLViewerTexture* tex);
+	void            switchTexture(U32 ch, LLViewerTexture* new_texture);
 	void            dirtyTexture();
 	LLXformMatrix*	getXform()			const	{ return mXform; }
 	BOOL			hasGeometry()		const	{ return mGeomCount > 0; }
 	LLVector3		getPositionAgent()	const;
-	LLVector2       surfaceToTexture(LLVector2 surface_coord, LLVector3 position, LLVector3 normal);
+	LLVector2       surfaceToTexture(LLVector2 surface_coord, const LLVector4a& position, const LLVector4a& normal);
 	void 			getPlanarProjectedParams(LLQuaternion* face_rot, LLVector3* face_pos, F32* scale) const;
 	bool			calcAlignedPlanarTE(const LLFace* align_to, LLVector2* st_offset,
 										LLVector2* st_scale, F32* st_rot) const;
@@ -130,8 +132,8 @@ class LLFace
 	F32				getVirtualSize() const { return mVSize; }
 	F32				getPixelArea() const { return mPixelArea; }
 
-	S32             getIndexInTex() const {return mIndexInTex ;}
-	void            setIndexInTex(S32 index) { mIndexInTex = index ;}
+	S32             getIndexInTex(U32 ch) const {llassert(ch < LLRender::NUM_TEXTURE_CHANNELS); return mIndexInTex[ch];}
+	void            setIndexInTex(U32 ch, S32 index) { llassert(ch < LLRender::NUM_TEXTURE_CHANNELS);  mIndexInTex[ch] = index ;}
 
 	void			renderSetColor() const;
 	S32				renderElements(const U16 *index_array) const;
@@ -149,7 +151,7 @@ class LLFace
 	S32				getLOD()			const	{ return mVObjp.notNull() ? mVObjp->getLOD() : 0; }
 	void			setPoolType(U32 type)		{ mPoolType = type; }
 	S32				getTEOffset()				{ return mTEOffset; }
-	LLViewerTexture*	getTexture() const;
+	LLViewerTexture*	getTexture(U32 ch = LLRender::DIFFUSE_MAP) const;
 
 	void			setViewerObject(LLViewerObject* object);
 	void			setPool(LLFacePool *pool, LLViewerTexture *texturep);
@@ -223,16 +225,6 @@ class LLFace
 	void        setHasMedia(bool has_media)  { mHasMedia = has_media ;}
 	BOOL        hasMedia() const ;
 
-	//for atlas
-	LLTextureAtlasSlot*   getAtlasInfo() ;
-	void                  setAtlasInUse(BOOL flag);
-	void                  setAtlasInfo(LLTextureAtlasSlot* atlasp);
-	BOOL                  isAtlasInUse()const;
-	BOOL                  canUseAtlas() const;
-	const LLVector2*      getTexCoordScale() const ;
-	const LLVector2*      getTexCoordOffset()const;
-	const LLTextureAtlas* getAtlas()const ;
-	void                  removeAtlas() ;
 	BOOL                  switchTexture() ;
 
 	//vertex buffer tracking
@@ -266,6 +258,8 @@ class LLFace
 	F32			mLastSkinTime;
 	F32			mLastMoveTime;
 	LLMatrix4*	mTextureMatrix;
+	LLMatrix4*	mSpecMapMatrix;
+	LLMatrix4*	mNormalMapMatrix;
 	LLDrawInfo* mDrawInfo;
 
 private:
@@ -281,10 +275,12 @@ class LLFace
 	U8			mTextureIndex;		// index of texture channel to use for pseudo-atlasing
 	U32			mIndicesCount;
 	U32			mIndicesIndex;		// index into draw pool for indices (yeah, I know!)
-	S32         mIndexInTex ;
+	S32         mIndexInTex[LLRender::NUM_TEXTURE_CHANNELS];
 
 	LLXformMatrix* mXform;
-	LLPointer<LLViewerTexture> mTexture;
+
+	LLPointer<LLViewerTexture> mTexture[LLRender::NUM_TEXTURE_CHANNELS];
+	
 	LLPointer<LLDrawable> mDrawablep;
 	LLPointer<LLViewerObject> mVObjp;
 	S32			mTEOffset;
@@ -302,9 +298,6 @@ class LLFace
 	F32         mBoundingSphereRadius ;
 	bool        mHasMedia ;
 
-	//atlas
-	LLPointer<LLTextureAtlasSlot> mAtlasInfop ;
-	BOOL                          mUsingAtlas ;
 	
 protected:
 	static BOOL	sSafeRenderSelect;
diff --git a/indra/newview/llfloaterimcontainer.cpp b/indra/newview/llfloaterimcontainer.cpp
index 58817485fb564dac0ff0296ec12aa73c7d299de4..b40789db9c1b91604f247520aadb622b924e70a5 100755
--- a/indra/newview/llfloaterimcontainer.cpp
+++ b/indra/newview/llfloaterimcontainer.cpp
@@ -2021,7 +2021,7 @@ void LLFloaterIMContainer::closeFloater(bool app_quitting/* = false*/)
 	{
 		LLMultiFloater::setMinimized(FALSE);
 	}
-	
+
 	LLFloater::closeFloater(app_quitting);
 }
 
diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp
index 49f36a2f321b1b1152a4f4eddf680fb4fff8d84a..56b0c15cb9e8ec03157270f9ef3e45ec0d04b085 100755
--- a/indra/newview/llfloaterimnearbychat.cpp
+++ b/indra/newview/llfloaterimnearbychat.cpp
@@ -328,7 +328,7 @@ void LLFloaterIMNearbyChat::onChatFontChange(LLFontGL* fontp)
 void LLFloaterIMNearbyChat::show()
 {
 		openFloater(getKey());
-}
+	}
 
 bool LLFloaterIMNearbyChat::isChatVisible() const
 {
diff --git a/indra/newview/llfloaterpreference.cpp b/indra/newview/llfloaterpreference.cpp
index bbf88060c1963c0601e1218d31312bd786cca8bb..55b03986d01098f3975c6121afbccb0b70727fb6 100755
--- a/indra/newview/llfloaterpreference.cpp
+++ b/indra/newview/llfloaterpreference.cpp
@@ -1089,8 +1089,9 @@ void LLFloaterPreference::refreshEnabledState()
 	ctrl_reflections->setEnabled(reflections);
 	
 	// Bump & Shiny	
+	LLCheckBoxCtrl* bumpshiny_ctrl = getChild<LLCheckBoxCtrl>("BumpShiny");
 	bool bumpshiny = gGLManager.mHasCubeMap && LLCubeMap::sUseCubeMaps && LLFeatureManager::getInstance()->isFeatureAvailable("RenderObjectBump");
-	getChild<LLCheckBoxCtrl>("BumpShiny")->setEnabled(bumpshiny ? TRUE : FALSE);
+	bumpshiny_ctrl->setEnabled(bumpshiny ? TRUE : FALSE);
 	
 	radio_reflection_detail->setEnabled(reflections);
 	
@@ -1148,7 +1149,8 @@ void LLFloaterPreference::refreshEnabledState()
 	//Deferred/SSAO/Shadows
 	LLCheckBoxCtrl* ctrl_deferred = getChild<LLCheckBoxCtrl>("UseLightShaders");
 	
-	BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") && 
+	BOOL enabled = LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
+						((bumpshiny_ctrl && bumpshiny_ctrl->get()) ? TRUE : FALSE) &&
 						shaders && 
 						gGLManager.mHasFramebufferObject &&
 						gSavedSettings.getBOOL("RenderAvatarVP") &&
@@ -1161,7 +1163,9 @@ void LLFloaterPreference::refreshEnabledState()
 	LLComboBox* ctrl_shadow = getChild<LLComboBox>("ShadowDetail");
 
 	enabled = enabled && LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferredSSAO") && (ctrl_deferred->get() ? TRUE : FALSE);
-		
+	
+	ctrl_deferred->set(gSavedSettings.getBOOL("RenderDeferred"));
+
 	ctrl_ssao->setEnabled(enabled);
 	ctrl_dof->setEnabled(enabled);
 
@@ -2319,3 +2323,4 @@ void LLFloaterPreferenceProxy::onChangeSocksSettings()
 	}
 
 }
+
diff --git a/indra/newview/llfriendcard.cpp b/indra/newview/llfriendcard.cpp
index 5c6ce9d311df02207c2f1edd8bb80bf293f9981a..16ed3f990c7cc13a4ff2b1604db0e64489b4982d 100755
--- a/indra/newview/llfriendcard.cpp
+++ b/indra/newview/llfriendcard.cpp
@@ -521,7 +521,7 @@ class CreateFriendCardCallback : public LLInventoryCallback
 	void fire(const LLUUID& inv_item_id)
 	{
 		LLViewerInventoryItem* item = gInventory.getItem(inv_item_id);
-		
+
 		if (item)
 			LLFriendCardsManager::instance().extractAvatarID(item->getCreatorUUID());
 	}
diff --git a/indra/newview/llhudicon.cpp b/indra/newview/llhudicon.cpp
index 7e1025c41b4695d1fc195fa70670a6a10ecf5f21..825c2b31bef19382ed6ba6053e76c04ccf37814f 100755
--- a/indra/newview/llhudicon.cpp
+++ b/indra/newview/llhudicon.cpp
@@ -202,7 +202,7 @@ void LLHUDIcon::render()
 	renderIcon(FALSE);
 }
 
-BOOL LLHUDIcon::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, LLVector3* intersection)
+BOOL LLHUDIcon::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, LLVector4a* intersection)
 {
 	if (mHidden)
 		return FALSE;
@@ -275,23 +275,18 @@ BOOL LLHUDIcon::lineSegmentIntersect(const LLVector3& start, const LLVector3& en
 	LLVector4a upper_right;
 	upper_right.setAdd(lower_right, y_scalea);
 
-	LLVector4a enda;
-	enda.load3(end.mV);
-	LLVector4a starta;
-	starta.load3(start.mV);
 	LLVector4a dir;
-	dir.setSub(enda, starta);
+	dir.setSub(end, start);
 
 	F32 a,b,t;
 
-	if (LLTriangleRayIntersect(upper_right, upper_left, lower_right, starta, dir, a,b,t) ||
-		LLTriangleRayIntersect(upper_left, lower_left, lower_right, starta, dir, a,b,t))
+	if (LLTriangleRayIntersect(upper_right, upper_left, lower_right, start, dir, a,b,t) ||
+		LLTriangleRayIntersect(upper_left, lower_left, lower_right, start, dir, a,b,t))
 	{
 		if (intersection)
 		{
 			dir.mul(t);
-			starta.add(dir);
-			*intersection = LLVector3(starta.getF32ptr());
+			intersection->setAdd(start, dir);
 		}
 		return TRUE;
 	}
@@ -331,12 +326,12 @@ LLHUDIcon* LLHUDIcon::handlePick(S32 pick_id)
 }
 
 //static
-LLHUDIcon* LLHUDIcon::lineSegmentIntersectAll(const LLVector3& start, const LLVector3& end, LLVector3* intersection)
+LLHUDIcon* LLHUDIcon::lineSegmentIntersectAll(const LLVector4a& start, const LLVector4a& end, LLVector4a* intersection)
 {
 	icon_instance_t::iterator icon_it;
 
-	LLVector3 local_end = end;
-	LLVector3 position;
+	LLVector4a local_end = end;
+	LLVector4a position;
 
 	LLHUDIcon* ret = NULL;
 	for(icon_it = sIconInstances.begin(); icon_it != sIconInstances.end(); ++icon_it)
diff --git a/indra/newview/llhudicon.h b/indra/newview/llhudicon.h
index 644daa02997995e0200213fced30926ced785abc..557252ab0bf392aed09ec86661260de0e6b75c0d 100755
--- a/indra/newview/llhudicon.h
+++ b/indra/newview/llhudicon.h
@@ -62,7 +62,7 @@ friend class LLHUDObject;
 
 	static S32 generatePickIDs(S32 start_id, S32 step_size);
 	static LLHUDIcon* handlePick(S32 pick_id);
-	static LLHUDIcon* lineSegmentIntersectAll(const LLVector3& start, const LLVector3& end, LLVector3* intersection);
+	static LLHUDIcon* lineSegmentIntersectAll(const LLVector4a& start, const LLVector4a& end, LLVector4a* intersection);
 
 	static void updateAll();
 	static void cleanupDeadIcons();
@@ -73,7 +73,7 @@ friend class LLHUDObject;
 	BOOL getHidden() const { return mHidden; }
 	void setHidden( BOOL hide ) { mHidden = hide; }
 
-	BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, LLVector3* intersection);
+	BOOL lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, LLVector4a* intersection);
 
 protected:
 	LLHUDIcon(const U8 type);
diff --git a/indra/newview/llhudnametag.cpp b/indra/newview/llhudnametag.cpp
index 33360979558ff345bff4dcc2b2c1254e08ee156c..c3b49f739aa183d0aa881ba8701dfb1305172077 100755
--- a/indra/newview/llhudnametag.cpp
+++ b/indra/newview/llhudnametag.cpp
@@ -116,7 +116,7 @@ LLHUDNameTag::~LLHUDNameTag()
 }
 
 
-BOOL LLHUDNameTag::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, LLVector3& intersection, BOOL debug_render)
+BOOL LLHUDNameTag::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, LLVector4a& intersection, BOOL debug_render)
 {
 	if (!mVisible || mHidden)
 	{
@@ -199,15 +199,23 @@ BOOL LLHUDNameTag::lineSegmentIntersect(const LLVector3& start, const LLVector3&
 		bg_pos + height_vec,
 	};
 
-	LLVector3 dir = end-start;
+	LLVector4a dir;
+	dir.setSub(end,start);
 	F32 a, b, t;
 
-	if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, a, b, t, FALSE) ||
-		LLTriangleRayIntersect(v[2], v[3], v[0], start, dir, a, b, t, FALSE) )
+	LLVector4a v0,v1,v2,v3;
+	v0.load3(v[0].mV);
+	v1.load3(v[1].mV);
+	v2.load3(v[2].mV);
+	v3.load3(v[3].mV);
+
+	if (LLTriangleRayIntersect(v0, v1, v2, start, dir, a, b, t) ||
+		LLTriangleRayIntersect(v2, v3, v0, start, dir, a, b, t) )
 	{
 		if (t <= 1.f)
 		{
-			intersection = start + dir*t;
+			dir.mul(t);
+			intersection.setAdd(start, dir);
 			return TRUE;
 		}
 	}
diff --git a/indra/newview/llhudnametag.h b/indra/newview/llhudnametag.h
index 72647d5b262dbd7c952f74f63909932f23b7d644..38a4f184153c09eae0264e2a64aa098c00a77c2a 100755
--- a/indra/newview/llhudnametag.h
+++ b/indra/newview/llhudnametag.h
@@ -124,7 +124,7 @@ class LLHUDNameTag : public LLHUDObject
 	void setHidden( BOOL hide ) { mHidden = hide; }
 	void shift(const LLVector3& offset);
 
-	BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, LLVector3& intersection, BOOL debug_render = FALSE);
+	BOOL lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, LLVector4a& intersection, BOOL debug_render = FALSE);
 
 	static void shiftAll(const LLVector3& offset);
 	static void addPickable(std::set<LLViewerObject*> &pick_list);
diff --git a/indra/newview/llimview.cpp b/indra/newview/llimview.cpp
index 2c20409381d3331018c0b099d9a45ee7c62eb435..3b72ad3cd9f068084998185dc1cdcb5cfcd558cc 100755
--- a/indra/newview/llimview.cpp
+++ b/indra/newview/llimview.cpp
@@ -228,7 +228,7 @@ void on_new_message(const LLSD& msg)
     // 0. nothing - exit
     if (("none" == user_preferences ||
     		ON_TOP_AND_ITEM_IS_SELECTED == conversations_floater_status)
-    	    && session_floater->isMessagePaneExpanded())
+    	&& session_floater->isMessagePaneExpanded())
     {
     	return;
     }
@@ -1561,7 +1561,7 @@ class LLViewerChatterBoxInvitationAcceptResponder :
 	}
 
 	void errorWithContent(U32 statusNum, const std::string& reason, const LLSD& content)
-	{
+	{		
 		llwarns << "LLViewerChatterBoxInvitationAcceptResponder error [status:"
 				<< statusNum << "]: " << content << llendl;
 		//throw something back to the viewer here?
diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp
index f2b39e71863d35f0f962f47d78677b2031d90f75..d88e0c3192ea2f3081f62c4558d2a8d7b52b1966 100755
--- a/indra/newview/llinventorymodelbackgroundfetch.cpp
+++ b/indra/newview/llinventorymodelbackgroundfetch.cpp
@@ -686,23 +686,23 @@ void LLInventoryModelBackgroundFetch::bulkFetch()
 	{
 		if (folder_count)
 		{
-			std::string url = region->getCapability("FetchInventoryDescendents2");   			
+			std::string url = region->getCapability("FetchInventoryDescendents2");   
 			if ( !url.empty() )
 			{
-				mFetchCount++;
-				if (folder_request_body["folders"].size())
-				{
-					LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats);
-					LLHTTPClient::post(url, folder_request_body, fetcher, 300.0);
-				}
-				if (folder_request_body_lib["folders"].size())
-				{
-					std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2");
+			mFetchCount++;
+			if (folder_request_body["folders"].size())
+			{
+				LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body, recursive_cats);
+				LLHTTPClient::post(url, folder_request_body, fetcher, 300.0);
+			}
+			if (folder_request_body_lib["folders"].size())
+			{
+				std::string url_lib = gAgent.getRegion()->getCapability("FetchLibDescendents2");
 
-					LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats);
-					LLHTTPClient::post(url_lib, folder_request_body_lib, fetcher, 300.0);
-				}
-			}					
+				LLInventoryModelFetchDescendentsResponder *fetcher = new LLInventoryModelFetchDescendentsResponder(folder_request_body_lib, recursive_cats);
+				LLHTTPClient::post(url_lib, folder_request_body_lib, fetcher, 300.0);
+			}
+		}
 		}
 		if (item_count)
 		{
diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp
index 25df4889b0d69973132c69da1ad3b0517575b3ae..2d9385390b45bbd893d4a815b2712f035d6f2fdf 100755
--- a/indra/newview/lllocalbitmaps.cpp
+++ b/indra/newview/lllocalbitmaps.cpp
@@ -58,6 +58,8 @@
 #include "lltexlayerparams.h"
 #include "llvovolume.h"
 #include "llnotificationsutil.h"
+#include "pipeline.h"
+#include "llmaterialmgr.h"
 
 /*=======================================*/
 /*  Formal declarations, constants, etc. */
@@ -339,7 +341,12 @@ void LLLocalBitmap::replaceIDs(LLUUID old_id, LLUUID new_id)
 		return;
 	}
 
-	updateUserPrims(old_id, new_id);
+	// processing updates per channel; makes the process scalable.
+	// the only actual difference is in SetTE* call i.e. SetTETexture, SetTENormal, etc.
+	updateUserPrims(old_id, new_id, LLRender::DIFFUSE_MAP);
+	updateUserPrims(old_id, new_id, LLRender::NORMAL_MAP);
+	updateUserPrims(old_id, new_id, LLRender::SPECULAR_MAP);
+	
 	updateUserSculpts(old_id, new_id); // isn't there supposed to be an IMG_DEFAULT_SCULPT or something?
 	
 	// default safeguard image for layers
@@ -367,15 +374,15 @@ void LLLocalBitmap::replaceIDs(LLUUID old_id, LLUUID new_id)
 
 // this function sorts the faces from a getFaceList[getNumFaces] into a list of objects
 // in order to prevent multiple sendTEUpdate calls per object during updateUserPrims
-std::vector<LLViewerObject*> LLLocalBitmap::prepUpdateObjects(LLUUID old_id)
+std::vector<LLViewerObject*> LLLocalBitmap::prepUpdateObjects(LLUUID old_id, U32 channel)
 {
 	std::vector<LLViewerObject*> obj_list;
 	LLViewerFetchedTexture* old_texture = gTextureList.findImage(old_id);
-
-	for(U32 face_iterator = 0; face_iterator < old_texture->getNumFaces(); face_iterator++)
+	
+	for(U32 face_iterator = 0; face_iterator < old_texture->getNumFaces(channel); face_iterator++)
 	{
 		// getting an object from a face
-		LLFace* face_to_object = (*old_texture->getFaceList())[face_iterator];
+		LLFace* face_to_object = (*old_texture->getFaceList(channel))[face_iterator];
 
 		if(face_to_object)
 		{
@@ -416,9 +423,9 @@ std::vector<LLViewerObject*> LLLocalBitmap::prepUpdateObjects(LLUUID old_id)
 	return obj_list;
 }
 
-void LLLocalBitmap::updateUserPrims(LLUUID old_id, LLUUID new_id)
+void LLLocalBitmap::updateUserPrims(LLUUID old_id, LLUUID new_id, U32 channel)
 {
-	std::vector<LLViewerObject*> objectlist = prepUpdateObjects(old_id);
+	std::vector<LLViewerObject*> objectlist = prepUpdateObjects(old_id, channel);
 
 	for(std::vector<LLViewerObject*>::iterator object_iterator = objectlist.begin();
 		object_iterator != objectlist.end(); object_iterator++)
@@ -427,7 +434,8 @@ void LLLocalBitmap::updateUserPrims(LLUUID old_id, LLUUID new_id)
 
 		if(object)
 		{
-			bool update_obj = false;
+			bool update_tex = false;
+			bool update_mat = false;
 			S32 num_faces = object->getNumFaces();
 
 			for (U8 face_iter = 0; face_iter < num_faces; face_iter++)
@@ -435,20 +443,51 @@ void LLLocalBitmap::updateUserPrims(LLUUID old_id, LLUUID new_id)
 				if (object->mDrawable)
 				{
 					LLFace* face = object->mDrawable->getFace(face_iter);
-					if (face && face->getTexture() && face->getTexture()->getID() == old_id)
+					if (face && face->getTexture(channel) && face->getTexture(channel)->getID() == old_id)
 					{
-						object->setTEImage(face_iter, LLViewerTextureManager::getFetchedTexture(
-							new_id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE));
+						// these things differ per channel, unless there already is a universal
+						// texture setting function to setTE that takes channel as a param?
+						// p.s.: switch for now, might become if - if an extra test is needed to verify before touching normalmap/specmap
+						switch(channel)
+						{
+							case LLRender::DIFFUSE_MAP:
+							{
+                                object->setTETexture(face_iter, new_id);
+                                update_tex = true;
+								break;
+							}
+
+							case LLRender::NORMAL_MAP:
+							{
+								object->setTENormalMap(face_iter, new_id);
+								update_mat = true;
+								update_tex = true;
+                                break;
+							}
+
+							case LLRender::SPECULAR_MAP:
+							{
+								object->setTESpecularMap(face_iter, new_id);
+                                update_mat = true;
+								update_tex = true;
+                                break;
+							}
+						}
+						// end switch
 
-						update_obj = true;
 					}
 				}
 			}
 			
-			if (update_obj)
+			if (update_tex)
 			{
 				object->sendTEUpdate();
 			}
+
+			if (update_mat)
+			{
+                object->mDrawable->getVOVolume()->faceMappingChanged();
+			}
 		}
 	}
 	
diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h
index 580b6dfa7e06ffff4ded45e3247b10a59c9bc8e2..2ee84bf46e72970d7283df83ba6b4096860f839f 100755
--- a/indra/newview/lllocalbitmaps.h
+++ b/indra/newview/lllocalbitmaps.h
@@ -62,8 +62,8 @@ class LLLocalBitmap
 	private: /* self update private section */
 		bool decodeBitmap(LLPointer<LLImageRaw> raw);
 		void replaceIDs(LLUUID old_id, LLUUID new_id);
-		std::vector<LLViewerObject*> prepUpdateObjects(LLUUID old_id);
-		void updateUserPrims(LLUUID old_id, LLUUID new_id);
+		std::vector<LLViewerObject*> prepUpdateObjects(LLUUID old_id, U32 channel);
+		void updateUserPrims(LLUUID old_id, LLUUID new_id, U32 channel);
 		void updateUserSculpts(LLUUID old_id, LLUUID new_id);
 		void updateUserLayers(LLUUID old_id, LLUUID new_id, LLWearableType::EType type);
 		LLAvatarAppearanceDefines::ETextureIndex getTexIndex(LLWearableType::EType type, LLAvatarAppearanceDefines::EBakedTextureIndex baked_texind);
diff --git a/indra/newview/lllogininstance.cpp b/indra/newview/lllogininstance.cpp
index 977c50682fede30b98cb850f9c540d6df21ba9d2..f681c127474933238fa6100e10a4484a38c0e178 100755
--- a/indra/newview/lllogininstance.cpp
+++ b/indra/newview/lllogininstance.cpp
@@ -642,6 +642,8 @@ bool LLLoginInstance::handleLoginEvent(const LLSD& event)
 
 void LLLoginInstance::handleLoginFailure(const LLSD& event)
 {
+	
+
 	// Login has failed. 
 	// Figure out why and respond...
 	LLSD response = event["data"];
@@ -654,10 +656,13 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
 	// to reconnect or to end the attempt in failure.
 	if(reason_response == "tos")
 	{
+		llinfos << "LLLoginInstance::handleLoginFailure ToS" << llendl;
+
 		LLSD data(LLSD::emptyMap());
 		data["message"] = message_response;
 		data["reply_pump"] = TOS_REPLY_PUMP;
-		gViewerWindow->setShowProgress(FALSE);
+		if (gViewerWindow)
+			gViewerWindow->setShowProgress(FALSE);
 		LLFloaterReg::showInstance("message_tos", data);
 		LLEventPumps::instance().obtain(TOS_REPLY_PUMP)
 			.listen(TOS_LISTENER_NAME,
@@ -666,6 +671,8 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
 	}
 	else if(reason_response == "critical")
 	{
+		llinfos << "LLLoginInstance::handleLoginFailure Crit" << llendl;
+
 		LLSD data(LLSD::emptyMap());
 		data["message"] = message_response;
 		data["reply_pump"] = TOS_REPLY_PUMP;
@@ -678,7 +685,9 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
 			data["certificate"] = response["certificate"];
 		}
 		
-		gViewerWindow->setShowProgress(FALSE);
+		if (gViewerWindow)
+			gViewerWindow->setShowProgress(FALSE);
+
 		LLFloaterReg::showInstance("message_critical", data);
 		LLEventPumps::instance().obtain(TOS_REPLY_PUMP)
 			.listen(TOS_LISTENER_NAME,
@@ -687,21 +696,28 @@ void LLLoginInstance::handleLoginFailure(const LLSD& event)
 	}
 	else if(reason_response == "update" || gSavedSettings.getBOOL("ForceMandatoryUpdate"))
 	{
+		llinfos << "LLLoginInstance::handleLoginFailure update" << llendl;
+
 		gSavedSettings.setBOOL("ForceMandatoryUpdate", FALSE);
 		updateApp(true, message_response);
 	}
 	else if(reason_response == "optional")
 	{
+		llinfos << "LLLoginInstance::handleLoginFailure optional" << llendl;
+
 		updateApp(false, message_response);
 	}
 	else
 	{	
+		llinfos << "LLLoginInstance::handleLoginFailure attemptComplete" << llendl;
 		attemptComplete();
 	}	
 }
 
 void LLLoginInstance::handleLoginSuccess(const LLSD& event)
 {
+	llinfos << "LLLoginInstance::handleLoginSuccess" << llendl;
+
 	if(gSavedSettings.getBOOL("ForceMandatoryUpdate"))
 	{
 		LLSD response = event["data"];
@@ -723,6 +739,8 @@ void LLLoginInstance::handleLoginSuccess(const LLSD& event)
 void LLLoginInstance::handleDisconnect(const LLSD& event)
 {
     // placeholder
+
+	llinfos << "LLLoginInstance::handleDisconnect placeholder " << llendl;
 }
 
 void LLLoginInstance::handleIndeterminate(const LLSD& event)
@@ -731,10 +749,13 @@ void LLLoginInstance::handleIndeterminate(const LLSD& event)
 	// gave the viewer a new url and params to try.
 	// The login module handles the retry, but it gives us the
 	// server response so that we may show
-	// the user some status.
+	// the user some status.	
+
 	LLSD message = event.get("data").get("message");
 	if(message.isDefined())
 	{
+		llinfos << "LLLoginInstance::handleIndeterminate " << message.asString() << llendl;
+
 		LLSD progress_update;
 		progress_update["desc"] = message;
 		LLEventPumps::getInstance()->obtain("LLProgressView").post(progress_update);
@@ -745,12 +766,16 @@ bool LLLoginInstance::handleTOSResponse(bool accepted, const std::string& key)
 {
 	if(accepted)
 	{	
+		llinfos << "LLLoginInstance::handleTOSResponse: accepted" << llendl;
+
 		// Set the request data to true and retry login.
 		mRequestData["params"][key] = true; 
 		reconnect();
 	}
 	else
 	{
+		llinfos << "LLLoginInstance::handleTOSResponse: attemptComplete" << llendl;
+
 		attemptComplete();
 	}
 
diff --git a/indra/newview/llmaterialmgr.cpp b/indra/newview/llmaterialmgr.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..16871adc4d568fe1522da6227ade681b8003856d
--- /dev/null
+++ b/indra/newview/llmaterialmgr.cpp
@@ -0,0 +1,782 @@
+/**
+ * @file llmaterialmgr.cpp
+ * @brief Material manager
+ *
+ * $LicenseInfo:firstyear=2013&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2013, 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$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llsdserialize.h"
+#include "llsdutil.h"
+
+#include "llagent.h"
+#include "llcallbacklist.h"
+#include "llmaterialmgr.h"
+#include "llviewerobject.h"
+#include "llviewerobjectlist.h"
+#include "llviewerregion.h"
+#include "llworld.h"
+
+/**
+ * Materials cap parameters
+ */
+
+#define MATERIALS_CAPABILITY_NAME                 "RenderMaterials"
+
+#define MATERIALS_CAP_ZIP_FIELD                   "Zipped"
+
+#define MATERIALS_CAP_FULL_PER_FACE_FIELD         "FullMaterialsPerFace"
+#define MATERIALS_CAP_FACE_FIELD                  "Face"
+#define MATERIALS_CAP_MATERIAL_FIELD              "Material"
+#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
+ */
+
+class LLMaterialsResponder : public LLHTTPClient::Responder
+{
+public:
+	typedef boost::function<void (bool, const LLSD&)> CallbackFunction;
+
+	LLMaterialsResponder(const std::string& pMethod, const std::string& pCapabilityURL, CallbackFunction pCallback);
+	virtual ~LLMaterialsResponder();
+
+	virtual void result(const LLSD& pContent);
+	virtual void error(U32 pStatus, const std::string& pReason);
+
+private:
+	std::string      mMethod;
+	std::string      mCapabilityURL;
+	CallbackFunction mCallback;
+};
+
+LLMaterialsResponder::LLMaterialsResponder(const std::string& pMethod, const std::string& pCapabilityURL, CallbackFunction pCallback)
+	: LLHTTPClient::Responder()
+	, mMethod(pMethod)
+	, mCapabilityURL(pCapabilityURL)
+	, mCallback(pCallback)
+{
+}
+
+LLMaterialsResponder::~LLMaterialsResponder()
+{
+}
+
+void LLMaterialsResponder::result(const LLSD& pContent)
+{
+	LL_DEBUGS("Materials") << LL_ENDL;
+	mCallback(true, pContent);
+}
+
+void LLMaterialsResponder::error(U32 pStatus, const std::string& pReason)
+{
+	LL_WARNS("Materials")
+		<< "\n--------------------------------------------------------------------------\n"
+		<< mMethod << " Error[" << pStatus << "] cannot access cap '" << MATERIALS_CAPABILITY_NAME
+		<< "'\n  with url '" << mCapabilityURL	<< "' because " << pReason 
+		<< "\n--------------------------------------------------------------------------"
+		<< LL_ENDL;
+
+	LLSD emptyResult;
+	mCallback(false, emptyResult);
+}
+
+/**
+ * LLMaterialMgr class
+ */
+
+LLMaterialMgr::LLMaterialMgr()
+{
+	mMaterials.insert(std::pair<LLMaterialID, LLMaterialPtr>(LLMaterialID::null, LLMaterialPtr(NULL)));
+	gIdleCallbacks.addFunction(&LLMaterialMgr::onIdle, NULL);
+	LLWorld::instance().setRegionRemovedCallback(boost::bind(&LLMaterialMgr::onRegionRemoved, this, _1));
+}
+
+LLMaterialMgr::~LLMaterialMgr()
+{
+	gIdleCallbacks.deleteFunction(&LLMaterialMgr::onIdle, NULL);
+}
+
+bool LLMaterialMgr::isGetPending(const LLUUID& region_id, const LLMaterialID& material_id) const
+{
+	get_pending_map_t::const_iterator itPending = mGetPending.find(pending_material_t(region_id, material_id));
+	return (mGetPending.end() != itPending) && (LLFrameTimer::getTotalSeconds() < itPending->second + MATERIALS_POST_TIMEOUT);
+}
+
+void LLMaterialMgr::markGetPending(const LLUUID& region_id, const LLMaterialID& material_id)
+{
+	get_pending_map_t::iterator itPending = mGetPending.find(pending_material_t(region_id, material_id));
+	if (mGetPending.end() == itPending)
+	{
+		mGetPending.insert(std::pair<pending_material_t, F64>(pending_material_t(region_id, material_id), LLFrameTimer::getTotalSeconds()));
+	}
+	else
+	{
+		itPending->second = LLFrameTimer::getTotalSeconds();
+	}
+}
+
+const LLMaterialPtr LLMaterialMgr::get(const LLUUID& region_id, const LLMaterialID& material_id)
+{
+	LL_DEBUGS("Materials") << "region " << region_id << " material id " << material_id << LL_ENDL;
+	LLMaterialPtr material;
+	material_map_t::const_iterator itMaterial = mMaterials.find(material_id);
+	if (mMaterials.end() != itMaterial)
+	{
+		material = itMaterial->second;
+		LL_DEBUGS("Materials") << " found material " << LL_ENDL;
+	}
+	else
+	{
+		if (!isGetPending(region_id, material_id))
+		{
+			LL_DEBUGS("Materials") << " material pending " << material_id << LL_ENDL;
+			get_queue_t::iterator itQueue = mGetQueue.find(region_id);
+			if (mGetQueue.end() == itQueue)
+			{
+				LL_DEBUGS("Materials") << "mGetQueue add region " << region_id << " pending " << material_id << LL_ENDL;
+				std::pair<get_queue_t::iterator, bool> ret = mGetQueue.insert(std::pair<LLUUID, material_queue_t>(region_id, material_queue_t()));
+				itQueue = ret.first;
+			}
+			itQueue->second.insert(material_id);
+			markGetPending(region_id, material_id);
+		}
+		LL_DEBUGS("Materials") << " returning empty material " << LL_ENDL;
+		material = LLMaterialPtr();
+	}
+	return material;
+}
+
+boost::signals2::connection LLMaterialMgr::get(const LLUUID& region_id, const LLMaterialID& material_id, LLMaterialMgr::get_callback_t::slot_type cb)
+{
+	boost::signals2::connection connection;
+	
+	material_map_t::const_iterator itMaterial = mMaterials.find(material_id);
+	if (itMaterial != mMaterials.end())
+	{
+		LL_DEBUGS("Materials") << "region " << region_id << " found materialid " << material_id << LL_ENDL;
+		get_callback_t signal;
+		signal.connect(cb);
+		signal(material_id, itMaterial->second);
+		connection = boost::signals2::connection();
+	}
+	else
+	{
+		if (!isGetPending(region_id, material_id))
+		{
+			get_queue_t::iterator itQueue = mGetQueue.find(region_id);
+			if (mGetQueue.end() == itQueue)
+			{
+				LL_DEBUGS("Materials") << "mGetQueue inserting region "<<region_id << LL_ENDL;
+				std::pair<get_queue_t::iterator, bool> ret = mGetQueue.insert(std::pair<LLUUID, material_queue_t>(region_id, material_queue_t()));
+				itQueue = ret.first;
+			}
+			LL_DEBUGS("Materials") << "adding material id " << material_id << LL_ENDL;
+			itQueue->second.insert(material_id);
+			markGetPending(region_id, material_id);
+		}
+
+		get_callback_map_t::iterator itCallback = mGetCallbacks.find(material_id);
+		if (itCallback == mGetCallbacks.end())
+		{
+			std::pair<get_callback_map_t::iterator, bool> ret = mGetCallbacks.insert(std::pair<LLMaterialID, get_callback_t*>(material_id, new get_callback_t()));
+			itCallback = ret.first;
+		}
+		connection = itCallback->second->connect(cb);;
+	}
+	
+	return connection;
+}
+
+boost::signals2::connection LLMaterialMgr::getTE(const LLUUID& region_id, const LLMaterialID& material_id, U32 te, LLMaterialMgr::get_callback_te_t::slot_type cb)
+{
+	boost::signals2::connection connection;
+
+	material_map_t::const_iterator itMaterial = mMaterials.find(material_id);
+	if (itMaterial != mMaterials.end())
+	{
+		LL_DEBUGS("Materials") << "region " << region_id << " found materialid " << material_id << LL_ENDL;
+		get_callback_te_t signal;
+		signal.connect(cb);
+		signal(material_id, itMaterial->second, te);
+		connection = boost::signals2::connection();
+	}
+	else
+	{
+		if (!isGetPending(region_id, material_id))
+		{
+			get_queue_t::iterator itQueue = mGetQueue.find(region_id);
+			if (mGetQueue.end() == itQueue)
+			{
+				LL_DEBUGS("Materials") << "mGetQueue inserting region "<<region_id << LL_ENDL;
+				std::pair<get_queue_t::iterator, bool> ret = mGetQueue.insert(std::pair<LLUUID, material_queue_t>(region_id, material_queue_t()));
+				itQueue = ret.first;
+			}
+			LL_DEBUGS("Materials") << "adding material id " << material_id << LL_ENDL;
+			itQueue->second.insert(material_id);
+			markGetPending(region_id, material_id);
+		}
+
+		TEMaterialPair te_mat_pair;
+		te_mat_pair.te = te;
+		te_mat_pair.materialID = material_id;
+
+		get_callback_te_map_t::iterator itCallback = mGetTECallbacks.find(te_mat_pair);
+		if (itCallback == mGetTECallbacks.end())
+		{
+			std::pair<get_callback_te_map_t::iterator, bool> ret = mGetTECallbacks.insert(std::pair<TEMaterialPair, get_callback_te_t*>(te_mat_pair, new get_callback_te_t()));
+			itCallback = ret.first;
+		}
+		connection = itCallback->second->connect(cb);
+	}
+
+	return connection;
+}
+
+bool LLMaterialMgr::isGetAllPending(const LLUUID& region_id) const
+{
+	getall_pending_map_t::const_iterator itPending = mGetAllPending.find(region_id);
+	return (mGetAllPending.end() != itPending) && (LLFrameTimer::getTotalSeconds() < itPending->second + MATERIALS_GET_TIMEOUT);
+}
+
+void LLMaterialMgr::getAll(const LLUUID& region_id)
+{
+	if (!isGetAllPending(region_id))
+	{
+		LL_DEBUGS("Materials") << "queuing for region " << region_id << LL_ENDL;
+		mGetAllQueue.insert(region_id);
+	}
+	else
+	{
+		LL_DEBUGS("Materials") << "already pending for region " << region_id << LL_ENDL;
+	}
+}
+
+boost::signals2::connection LLMaterialMgr::getAll(const LLUUID& region_id, LLMaterialMgr::getall_callback_t::slot_type cb)
+{
+	if (!isGetAllPending(region_id))
+	{
+		mGetAllQueue.insert(region_id);
+	}
+
+	getall_callback_map_t::iterator itCallback = mGetAllCallbacks.find(region_id);
+	if (mGetAllCallbacks.end() == itCallback)
+	{
+		std::pair<getall_callback_map_t::iterator, bool> ret = mGetAllCallbacks.insert(std::pair<LLUUID, getall_callback_t*>(region_id, new getall_callback_t()));
+		itCallback = ret.first;
+	}
+	return itCallback->second->connect(cb);;
+}
+
+void LLMaterialMgr::put(const LLUUID& object_id, const U8 te, const LLMaterial& material)
+{
+	put_queue_t::iterator itQueue = mPutQueue.find(object_id);
+	if (mPutQueue.end() == itQueue)
+	{
+		LL_DEBUGS("Materials") << "mPutQueue insert object " << object_id << LL_ENDL;
+		mPutQueue.insert(std::pair<LLUUID, facematerial_map_t>(object_id, facematerial_map_t()));
+		itQueue = mPutQueue.find(object_id);
+	}
+
+	facematerial_map_t::iterator itFace = itQueue->second.find(te);
+	if (itQueue->second.end() == itFace)
+	{
+		itQueue->second.insert(std::pair<U8, LLMaterial>(te, material));
+	}
+	else
+	{
+		itFace->second = material;
+	}
+}
+
+void LLMaterialMgr::remove(const LLUUID& object_id, const U8 te)
+{
+	put(object_id, te, LLMaterial::null);
+}
+
+const LLMaterialPtr LLMaterialMgr::setMaterial(const LLUUID& region_id, const LLMaterialID& material_id, const LLSD& material_data)
+{
+	LL_DEBUGS("Materials") << "region " << region_id << " material id " << material_id << LL_ENDL;
+	material_map_t::const_iterator itMaterial = mMaterials.find(material_id);
+	if (mMaterials.end() == itMaterial)
+	{
+		LL_DEBUGS("Materials") << "new material" << LL_ENDL;
+		LLMaterialPtr newMaterial(new LLMaterial(material_data));
+		std::pair<material_map_t::const_iterator, bool> ret = mMaterials.insert(std::pair<LLMaterialID, LLMaterialPtr>(material_id, newMaterial));
+		itMaterial = ret.first;
+	}
+
+	TEMaterialPair te_mat_pair;
+	te_mat_pair.materialID = material_id;
+
+	U32 i = 0;
+	while (i < LLTEContents::MAX_TES)
+	{
+		te_mat_pair.te = i++;
+		get_callback_te_map_t::iterator itCallbackTE = mGetTECallbacks.find(te_mat_pair);
+		if (itCallbackTE != mGetTECallbacks.end())
+		{
+			(*itCallbackTE->second)(material_id, itMaterial->second, te_mat_pair.te);
+			delete itCallbackTE->second;
+			mGetTECallbacks.erase(itCallbackTE);
+		}
+	}
+
+	get_callback_map_t::iterator itCallback = mGetCallbacks.find(material_id);
+	if (itCallback != mGetCallbacks.end())
+	{
+		(*itCallback->second)(material_id, itMaterial->second);
+
+		delete itCallback->second;
+		mGetCallbacks.erase(itCallback);
+	}
+
+	mGetPending.erase(pending_material_t(region_id, material_id));
+
+	return itMaterial->second;
+}
+
+void LLMaterialMgr::onGetResponse(bool success, const LLSD& content, const LLUUID& region_id)
+{
+	if (!success)
+	{
+		// *TODO: is there any kind of error handling we can do here?
+		LL_WARNS("Materials")<< "failed"<<LL_ENDL;
+		return;
+	}
+
+	llassert(content.isMap());
+	llassert(content.has(MATERIALS_CAP_ZIP_FIELD));
+	llassert(content[MATERIALS_CAP_ZIP_FIELD].isBinary());
+
+	LLSD::Binary content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();
+	std::string content_string(reinterpret_cast<const char*>(content_binary.data()), content_binary.size());
+	std::istringstream content_stream(content_string);
+
+	LLSD response_data;
+	if (!unzip_llsd(response_data, content_stream, content_binary.size()))
+	{
+		LL_WARNS("Materials") << "Cannot unzip LLSD binary content" << LL_ENDL;
+		return;
+	}
+
+	llassert(response_data.isArray());
+	LL_DEBUGS("Materials") << "response has "<< response_data.size() << " materials" << LL_ENDL;
+	for (LLSD::array_const_iterator itMaterial = response_data.beginArray(); itMaterial != response_data.endArray(); ++itMaterial)
+	{
+		const LLSD& material_data = *itMaterial;
+		llassert(material_data.isMap());
+
+		llassert(material_data.has(MATERIALS_CAP_OBJECT_ID_FIELD));
+		llassert(material_data[MATERIALS_CAP_OBJECT_ID_FIELD].isBinary());
+		LLMaterialID material_id(material_data[MATERIALS_CAP_OBJECT_ID_FIELD].asBinary());
+
+		llassert(material_data.has(MATERIALS_CAP_MATERIAL_FIELD));
+		llassert(material_data[MATERIALS_CAP_MATERIAL_FIELD].isMap());
+			
+		setMaterial(region_id, material_id, material_data[MATERIALS_CAP_MATERIAL_FIELD]);
+	}
+}
+
+void LLMaterialMgr::onGetAllResponse(bool success, const LLSD& content, const LLUUID& region_id)
+{
+	if (!success)
+	{
+		// *TODO: is there any kind of error handling we can do here?
+		LL_WARNS("Materials")<< "failed"<<LL_ENDL;
+		return;
+	}
+
+	llassert(content.isMap());
+	llassert(content.has(MATERIALS_CAP_ZIP_FIELD));
+	llassert(content[MATERIALS_CAP_ZIP_FIELD].isBinary());
+
+	LLSD::Binary content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();
+	std::string content_string(reinterpret_cast<const char*>(content_binary.data()), content_binary.size());
+	std::istringstream content_stream(content_string);
+
+	LLSD response_data;
+	if (!unzip_llsd(response_data, content_stream, content_binary.size()))
+	{
+		LL_WARNS("Materials") << "Cannot unzip LLSD binary content" << LL_ENDL;
+		return;
+	}
+
+	get_queue_t::iterator itQueue = mGetQueue.find(region_id);
+	material_map_t materials;
+
+	llassert(response_data.isArray());
+	LL_DEBUGS("Materials") << "response has "<< response_data.size() << " materials" << LL_ENDL;
+	for (LLSD::array_const_iterator itMaterial = response_data.beginArray(); itMaterial != response_data.endArray(); ++itMaterial)
+	{
+		const LLSD& material_data = *itMaterial;
+		llassert(material_data.isMap());
+
+		llassert(material_data.has(MATERIALS_CAP_OBJECT_ID_FIELD));
+		llassert(material_data[MATERIALS_CAP_OBJECT_ID_FIELD].isBinary());
+		LLMaterialID material_id(material_data[MATERIALS_CAP_OBJECT_ID_FIELD].asBinary());
+		if (mGetQueue.end() != itQueue)
+		{
+			itQueue->second.erase(material_id);
+		}
+
+		llassert(material_data.has(MATERIALS_CAP_MATERIAL_FIELD));
+		llassert(material_data[MATERIALS_CAP_MATERIAL_FIELD].isMap());
+		LLMaterialPtr material = setMaterial(region_id, material_id, material_data[MATERIALS_CAP_MATERIAL_FIELD]);
+		
+		materials[material_id] = material;
+	}
+
+	getall_callback_map_t::iterator itCallback = mGetAllCallbacks.find(region_id);
+	if (itCallback != mGetAllCallbacks.end())
+	{
+		(*itCallback->second)(region_id, materials);
+
+		delete itCallback->second;
+		mGetAllCallbacks.erase(itCallback);
+	}
+
+	if ( (mGetQueue.end() != itQueue) && (itQueue->second.empty()) )
+	{
+		mGetQueue.erase(itQueue);
+	}
+
+	LL_DEBUGS("Materials")<< "recording that getAll has been done for region id " << region_id << LL_ENDL;	
+	mGetAllRequested.insert(region_id); // prevents subsequent getAll requests for this region
+	mGetAllPending.erase(region_id);	// Invalidates region_id
+}
+
+void LLMaterialMgr::onPutResponse(bool success, const LLSD& content)
+{
+	if (!success)
+	{
+		// *TODO: is there any kind of error handling we can do here?
+		LL_WARNS("Materials")<< "failed"<<LL_ENDL;
+		return;
+	}
+
+	llassert(content.isMap());
+	llassert(content.has(MATERIALS_CAP_ZIP_FIELD));
+	llassert(content[MATERIALS_CAP_ZIP_FIELD].isBinary());
+
+	LLSD::Binary content_binary = content[MATERIALS_CAP_ZIP_FIELD].asBinary();
+	std::string content_string(reinterpret_cast<const char*>(content_binary.data()), content_binary.size());
+	std::istringstream content_stream(content_string);
+
+	LLSD response_data;
+	if (!unzip_llsd(response_data, content_stream, content_binary.size()))
+	{
+		LL_WARNS("Materials") << "Cannot unzip LLSD binary content" << LL_ENDL;
+		return;
+	}
+	else
+	{
+		llassert(response_data.isArray());
+		LL_DEBUGS("Materials") << "response has "<< response_data.size() << " materials" << LL_ENDL;
+		for (LLSD::array_const_iterator faceIter = response_data.beginArray(); faceIter != response_data.endArray(); ++faceIter)
+		{
+#           ifndef LL_RELEASE_FOR_DOWNLOAD
+			const LLSD& face_data = *faceIter; // conditional to avoid unused variable warning
+#           endif
+			llassert(face_data.isMap());
+
+			llassert(face_data.has(MATERIALS_CAP_OBJECT_ID_FIELD));
+			llassert(face_data[MATERIALS_CAP_OBJECT_ID_FIELD].isInteger());
+			// U32 local_id = face_data[MATERIALS_CAP_OBJECT_ID_FIELD].asInteger();
+
+			llassert(face_data.has(MATERIALS_CAP_FACE_FIELD));
+			llassert(face_data[MATERIALS_CAP_FACE_FIELD].isInteger());
+			// S32 te = face_data[MATERIALS_CAP_FACE_FIELD].asInteger();
+
+			llassert(face_data.has(MATERIALS_CAP_MATERIAL_ID_FIELD));
+			llassert(face_data[MATERIALS_CAP_MATERIAL_ID_FIELD].isBinary());
+			// LLMaterialID material_id(face_data[MATERIALS_CAP_MATERIAL_ID_FIELD].asBinary());
+
+			// *TODO: do we really still need to process this?
+		}
+	}
+}
+
+static LLFastTimer::DeclareTimer FTM_MATERIALS_IDLE("Materials");
+
+void LLMaterialMgr::onIdle(void*)
+{
+	LLFastTimer t(FTM_MATERIALS_IDLE);
+
+	LLMaterialMgr* instancep = LLMaterialMgr::getInstance();
+
+	if (!instancep->mGetQueue.empty())
+	{
+		instancep->processGetQueue();
+	}
+
+	if (!instancep->mGetAllQueue.empty())
+	{
+		instancep->processGetAllQueue();
+	}
+
+	static LLFrameTimer mPutTimer;
+	if ( (!instancep->mPutQueue.empty()) && (mPutTimer.hasExpired()) )
+	{
+		instancep->processPutQueue();
+		mPutTimer.resetWithExpiry(MATERIALS_PUT_THROTTLE_SECS);
+	}
+}
+
+void LLMaterialMgr::processGetQueue()
+{
+	get_queue_t::iterator loopRegionQueue = mGetQueue.begin();
+	while (mGetQueue.end() != loopRegionQueue)
+	{
+		get_queue_t::iterator itRegionQueue = loopRegionQueue++;
+
+		const LLUUID& region_id = itRegionQueue->first;
+		if (isGetAllPending(region_id))
+		{
+			continue;
+		}
+
+		const 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())
+		{
+			continue;
+		}
+		else if (mGetAllRequested.end() == mGetAllRequested.find(region_id))
+		{
+			LL_DEBUGS("Materials") << "calling getAll for " << regionp->getName() << LL_ENDL;
+			getAll(region_id);
+			continue;
+		}
+
+		const std::string capURL = regionp->getCapability(MATERIALS_CAPABILITY_NAME);
+		if (capURL.empty())
+		{
+			LL_WARNS("Materials") << "Capability '" << MATERIALS_CAPABILITY_NAME
+				<< "' is not defined on region '" << regionp->getName() << "'" << LL_ENDL;
+			mGetQueue.erase(itRegionQueue);
+			continue;
+		}
+
+		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) )
+		{
+			material_queue_t::iterator itMaterial = loopMaterial++;
+			materialsData.append((*itMaterial).asLLSD());
+			materials.erase(itMaterial);
+			markGetPending(region_id, *itMaterial);
+		}
+		if (materials.empty())
+		{
+			mGetQueue.erase(itRegionQueue);
+		}
+		
+		std::string materialString = zip_llsd(materialsData);
+
+		S32 materialSize = materialString.size();
+		if (materialSize <= 0)
+		{
+			LL_ERRS("Materials") << "cannot zip LLSD binary content" << LL_ENDL;
+			return;
+		}
+
+		LLSD::Binary materialBinary;
+		materialBinary.resize(materialSize);
+		memcpy(materialBinary.data(), materialString.data(), materialSize);
+
+		LLSD postData = LLSD::emptyMap();
+		postData[MATERIALS_CAP_ZIP_FIELD] = materialBinary;
+
+		LLHTTPClient::ResponderPtr materialsResponder = new LLMaterialsResponder("POST", capURL, boost::bind(&LLMaterialMgr::onGetResponse, this, _1, _2, region_id));
+		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);
+	}
+}
+
+void LLMaterialMgr::processGetAllQueue()
+{
+	getall_queue_t::iterator loopRegion = mGetAllQueue.begin();
+	while (mGetAllQueue.end() != loopRegion)
+	{
+		getall_queue_t::iterator itRegion = loopRegion++;
+
+		const LLUUID& region_id = *itRegion;
+		LLViewerRegion* regionp = LLWorld::instance().getRegionFromID(region_id);
+		if (regionp == NULL)
+		{
+			LL_WARNS("Materials") << "Unknown region with id " << region_id.asString() << LL_ENDL;
+			clearGetQueues(region_id);		// Invalidates region_id
+			continue;
+		}
+		else if (!regionp->capabilitiesReceived())
+		{
+			continue;
+		}
+
+		std::string capURL = regionp->getCapability(MATERIALS_CAPABILITY_NAME);
+		if (capURL.empty())
+		{
+			LL_WARNS("Materials") << "Capability '" << MATERIALS_CAPABILITY_NAME
+				<< "' is not defined on the current region '" << regionp->getName() << "'" << LL_ENDL;
+			clearGetQueues(region_id);		// Invalidates region_id
+			continue;
+		}
+
+		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);
+		mGetAllPending.insert(std::pair<LLUUID, F64>(region_id, LLFrameTimer::getTotalSeconds()));
+		mGetAllQueue.erase(itRegion);	// Invalidates region_id
+	}
+}
+
+void LLMaterialMgr::processPutQueue()
+{
+	typedef std::map<const LLViewerRegion*, LLSD> regionput_request_map;
+	regionput_request_map requests;
+
+	put_queue_t::iterator loopQueue = mPutQueue.begin();
+	while (mPutQueue.end() != loopQueue)
+	{
+		put_queue_t::iterator itQueue = loopQueue++;
+
+		const LLUUID& object_id = itQueue->first;
+		const LLViewerObject* objectp = gObjectList.findObject(object_id);
+		if ( (!objectp) || (!objectp->getRegion()) )
+		{
+			LL_WARNS("Materials") << "Object or object region 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) )
+		{
+			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);
+		}
+	}
+
+	for (regionput_request_map::const_iterator itRequest = requests.begin(); itRequest != requests.end(); ++itRequest)
+	{
+		std::string capURL = itRequest->first->getCapability(MATERIALS_CAPABILITY_NAME);
+		if (capURL.empty())
+		{
+			LL_WARNS("Materials") << "Capability '" << MATERIALS_CAPABILITY_NAME
+				<< "' is not defined on region '" << itRequest->first->getName() << "'" << LL_ENDL;
+			continue;
+		}
+
+		LLSD materialsData = LLSD::emptyMap();
+		materialsData[MATERIALS_CAP_FULL_PER_FACE_FIELD] = itRequest->second;
+
+		std::string materialString = zip_llsd(materialsData);
+
+		S32 materialSize = materialString.size();
+
+		if (materialSize > 0)
+		{
+			LLSD::Binary materialBinary;
+			materialBinary.resize(materialSize);
+			memcpy(materialBinary.data(), materialString.data(), materialSize);
+
+			LLSD putData = LLSD::emptyMap();
+			putData[MATERIALS_CAP_ZIP_FIELD] = materialBinary;
+
+			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);
+		}
+		else
+		{
+			LL_ERRS("debugMaterials") << "cannot zip LLSD binary content" << LL_ENDL;
+		}
+	}
+}
+
+void LLMaterialMgr::clearGetQueues(const LLUUID& region_id)
+{
+	mGetQueue.erase(region_id);
+	for (get_pending_map_t::iterator itPending = mGetPending.begin(); itPending != mGetPending.end();)
+	{
+		if (region_id == itPending->first.first)
+		{
+			mGetPending.erase(itPending++);
+		}
+		else
+		{
+			++itPending;
+		}
+	}
+
+	mGetAllQueue.erase(region_id);
+	mGetAllRequested.erase(region_id);
+	mGetAllPending.erase(region_id);
+	mGetAllCallbacks.erase(region_id);
+}
+
+void LLMaterialMgr::onRegionRemoved(LLViewerRegion* regionp)
+{
+	clearGetQueues(regionp->getRegionID());
+	// Put doesn't need clearing: objects that can't be found will clean up in processPutQueue()
+}
+
diff --git a/indra/newview/llmaterialmgr.h b/indra/newview/llmaterialmgr.h
new file mode 100644
index 0000000000000000000000000000000000000000..e317a791adfe1b2ae47af55e19b520f7ad04a977
--- /dev/null
+++ b/indra/newview/llmaterialmgr.h
@@ -0,0 +1,130 @@
+/**
+ * @file llmaterialmgr.h
+ * @brief Material manager
+ *
+ * $LicenseInfo:firstyear=2006&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ * 
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ * 
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ * 
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLMATERIALMGR_H
+#define LL_LLMATERIALMGR_H
+
+#include "llmaterial.h"
+#include "llmaterialid.h"
+#include "llsingleton.h"
+
+class LLViewerRegion;
+
+class LLMaterialMgr : public LLSingleton<LLMaterialMgr>
+{
+	friend class LLSingleton<LLMaterialMgr>;
+protected:
+	LLMaterialMgr();
+	virtual ~LLMaterialMgr();
+
+public:
+	typedef std::map<LLMaterialID, LLMaterialPtr> material_map_t;
+
+	typedef boost::signals2::signal<void (const LLMaterialID&, const LLMaterialPtr)> get_callback_t;
+	const LLMaterialPtr         get(const LLUUID& region_id, const LLMaterialID& material_id);
+	boost::signals2::connection get(const LLUUID& region_id, const LLMaterialID& material_id, get_callback_t::slot_type cb);
+
+	typedef boost::signals2::signal<void (const LLMaterialID&, const LLMaterialPtr, U32 te)> get_callback_te_t;
+	boost::signals2::connection getTE(const LLUUID& region_id, const LLMaterialID& material_id, U32 te, get_callback_te_t::slot_type cb);
+
+	typedef boost::signals2::signal<void (const LLUUID&, const material_map_t&)> getall_callback_t;
+	void                        getAll(const LLUUID& region_id);
+	boost::signals2::connection getAll(const LLUUID& region_id, getall_callback_t::slot_type cb);
+	void put(const LLUUID& object_id, const U8 te, const LLMaterial& material);
+	void remove(const LLUUID& object_id, const U8 te);
+
+protected:
+	void clearGetQueues(const LLUUID& region_id);
+	bool isGetPending(const LLUUID& region_id, const LLMaterialID& material_id) const;
+	bool isGetAllPending(const LLUUID& region_id) const;
+	void markGetPending(const LLUUID& region_id, const LLMaterialID& material_id);
+	const LLMaterialPtr setMaterial(const LLUUID& region_id, const LLMaterialID& material_id, const LLSD& material_data);
+
+	static void onIdle(void*);
+	void processGetQueue();
+	void onGetResponse(bool success, const LLSD& content, const LLUUID& region_id);
+	void processGetAllQueue();
+	void onGetAllResponse(bool success, const LLSD& content, const LLUUID& region_id);
+	void processPutQueue();
+	void onPutResponse(bool success, const LLSD& content);
+	void onRegionRemoved(LLViewerRegion* regionp);
+
+protected:
+	typedef std::set<LLMaterialID> material_queue_t;
+	typedef std::map<LLUUID, material_queue_t> get_queue_t;
+	get_queue_t        mGetQueue;
+	typedef std::pair<const LLUUID, LLMaterialID> pending_material_t;
+	typedef std::map<const pending_material_t, F64> get_pending_map_t;
+	get_pending_map_t  mGetPending;
+	typedef std::map<LLMaterialID, get_callback_t*> get_callback_map_t;
+	get_callback_map_t mGetCallbacks;
+
+	// struct for TE-specific material ID query
+	class TEMaterialPair
+	{
+	public:
+
+		U32 te;
+		LLMaterialID materialID;
+
+		bool operator==(const TEMaterialPair& b) const { return (materialID == b.materialID) && (te == b.te); }
+	};
+	
+	friend inline bool operator<(
+		const LLMaterialMgr::TEMaterialPair& lhs,
+		const LLMaterialMgr::TEMaterialPair& rhs)
+	{
+		return (lhs.te	< rhs.te) ? TRUE :
+			(lhs.materialID < rhs.materialID);
+	}
+
+	struct TEMaterialPairHasher
+	{
+		enum { bucket_size = 8 };
+		size_t operator()(const TEMaterialPair& key_value) const { return *((size_t*)key_value.materialID.get());  } // cheesy, but effective
+		bool   operator()(const TEMaterialPair& left, const TEMaterialPair& right) const { return left < right; }
+	};
+
+	typedef boost::unordered_map<TEMaterialPair, get_callback_te_t*, TEMaterialPairHasher> get_callback_te_map_t;
+	get_callback_te_map_t mGetTECallbacks;
+
+	typedef std::set<LLUUID> getall_queue_t;
+	getall_queue_t        mGetAllQueue;
+	getall_queue_t        mGetAllRequested;
+	typedef std::map<LLUUID, F64> getall_pending_map_t;
+	getall_pending_map_t  mGetAllPending;
+	typedef std::map<LLUUID, getall_callback_t*> getall_callback_map_t;
+	getall_callback_map_t mGetAllCallbacks;
+
+	typedef std::map<U8, LLMaterial> facematerial_map_t;
+	typedef std::map<LLUUID, facematerial_map_t> put_queue_t;
+	put_queue_t mPutQueue;
+
+	material_map_t mMaterials;
+};
+
+#endif // LL_LLMATERIALMGR_H
+
diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp
index 913841ab7134982ffb039e9db87c509fe31dc390..2d003dd6d702754998a3e58492cd26ad192db384 100755
--- a/indra/newview/llmeshrepository.cpp
+++ b/indra/newview/llmeshrepository.cpp
@@ -1,3 +1,4 @@
+
 /** 
  * @file llmeshrepository.cpp
  * @brief Mesh repository implementation.
diff --git a/indra/newview/llpaneleditwearable.h b/indra/newview/llpaneleditwearable.h
index 6533d55f2fc6e1ea9cc141d0023689fd9e7a92ef..81acc31863d42b356d1ba8f5942ab47e348baf28 100755
--- a/indra/newview/llpaneleditwearable.h
+++ b/indra/newview/llpaneleditwearable.h
@@ -95,7 +95,7 @@ class LLPanelEditWearable : public LLPanel
 	void				toggleTypeSpecificControls(LLWearableType::EType type);
 	void				updateTypeSpecificControls(LLWearableType::EType type);
 
-	// alpha mask checkboxes
+	//alpha mask checkboxes
 	void configureAlphaCheckbox(LLAvatarAppearanceDefines::ETextureIndex te, const std::string& name);
 	void onInvisibilityCommit(LLCheckBoxCtrl* checkbox_ctrl, LLAvatarAppearanceDefines::ETextureIndex te);
 	void updateAlphaCheckboxes();
@@ -155,7 +155,7 @@ class LLPanelEditWearable : public LLPanel
 	LLPanel *mPanelEyes;
 	LLPanel *mPanelHair;
 
-	// clothes
+	//clothes
 	LLPanel *mPanelShirt;
 	LLPanel *mPanelPants;
 	LLPanel *mPanelShoes;
diff --git a/indra/newview/llpanelface.cpp b/indra/newview/llpanelface.cpp
index 445c0d811f202a76c7e701eb46e8440d84b6557d..911af9df049d4120e7a5ea74359bb0867fb9d189 100755
--- a/indra/newview/llpanelface.cpp
+++ b/indra/newview/llpanelface.cpp
@@ -46,6 +46,7 @@
 #include "lldrawpoolbump.h"
 #include "llface.h"
 #include "lllineeditor.h"
+#include "llmaterialmgr.h"
 #include "llmediaentry.h"
 #include "llnotificationsutil.h"
 #include "llresmgr.h"
@@ -55,16 +56,60 @@
 #include "lltexturectrl.h"
 #include "lltextureentry.h"
 #include "lltooldraganddrop.h"
+#include "lltrans.h"
 #include "llui.h"
 #include "llviewercontrol.h"
 #include "llviewermedia.h"
 #include "llviewerobject.h"
+#include "llviewerregion.h"
 #include "llviewerstats.h"
 #include "llvovolume.h"
 #include "lluictrlfactory.h"
 #include "llpluginclassmedia.h"
 #include "llviewertexturelist.h"
 
+//
+// Constant definitions for comboboxes
+// Must match the commbobox definitions in panel_tools_texture.xml
+//
+const S32 MATMEDIA_MATERIAL = 0;	// Material
+const S32 MATMEDIA_MEDIA = 1;		// Media
+const S32 MATTYPE_DIFFUSE = 0;		// Diffuse material texture
+const S32 MATTYPE_NORMAL = 1;		// Normal map
+const S32 MATTYPE_SPECULAR = 2;		// Specular map
+const S32 ALPHAMODE_NONE = 0;		// No alpha mask applied
+const S32 ALPHAMODE_BLEND = 1;		// Alpha blending mode
+const S32 ALPHAMODE_MASK = 2;		// Alpha masking mode
+const S32 BUMPY_TEXTURE = 18;		// use supplied normal map
+const S32 SHINY_TEXTURE = 4;		// use supplied specular map
+
+//
+// "Use texture" label for normal/specular type comboboxes
+// Filled in at initialization from translated strings
+//
+std::string USE_TEXTURE;
+
+// Things the UI provides...
+//
+LLUUID	LLPanelFace::getCurrentNormalMap()			{ return getChild<LLTextureCtrl>("bumpytexture control")->getImageAssetID();	}
+LLUUID	LLPanelFace::getCurrentSpecularMap()		{ return getChild<LLTextureCtrl>("shinytexture control")->getImageAssetID();	}
+U32		LLPanelFace::getCurrentShininess()			{ return getChild<LLComboBox>("combobox shininess")->getCurrentIndex();			}
+U32		LLPanelFace::getCurrentBumpiness()			{ return getChild<LLComboBox>("combobox bumpiness")->getCurrentIndex();			}
+U8			LLPanelFace::getCurrentDiffuseAlphaMode()	{ return (U8)getChild<LLComboBox>("combobox alphamode")->getCurrentIndex();	}
+U8			LLPanelFace::getCurrentAlphaMaskCutoff()	{ return (U8)getChild<LLUICtrl>("maskcutoff")->getValue().asInteger();			}
+U8			LLPanelFace::getCurrentEnvIntensity()		{ return (U8)getChild<LLUICtrl>("environment")->getValue().asInteger();			}
+U8			LLPanelFace::getCurrentGlossiness()			{ return (U8)getChild<LLUICtrl>("glossiness")->getValue().asInteger();			}
+F32		LLPanelFace::getCurrentBumpyRot()			{ return getChild<LLUICtrl>("bumpyRot")->getValue().asReal();						}
+F32		LLPanelFace::getCurrentBumpyScaleU()		{ return getChild<LLUICtrl>("bumpyScaleU")->getValue().asReal();					}
+F32		LLPanelFace::getCurrentBumpyScaleV()		{ return getChild<LLUICtrl>("bumpyScaleV")->getValue().asReal();					}
+F32		LLPanelFace::getCurrentBumpyOffsetU()		{ return getChild<LLUICtrl>("bumpyOffsetU")->getValue().asReal();					}
+F32		LLPanelFace::getCurrentBumpyOffsetV()		{ return getChild<LLUICtrl>("bumpyOffsetV")->getValue().asReal();					}
+F32		LLPanelFace::getCurrentShinyRot()			{ return getChild<LLUICtrl>("shinyRot")->getValue().asReal();						}
+F32		LLPanelFace::getCurrentShinyScaleU()		{ return getChild<LLUICtrl>("shinyScaleU")->getValue().asReal();					}
+F32		LLPanelFace::getCurrentShinyScaleV()		{ return getChild<LLUICtrl>("shinyScaleV")->getValue().asReal();					}
+F32		LLPanelFace::getCurrentShinyOffsetU()		{ return getChild<LLUICtrl>("shinyOffsetU")->getValue().asReal();					}
+F32		LLPanelFace::getCurrentShinyOffsetV()		{ return getChild<LLUICtrl>("shinyOffsetV")->getValue().asReal();					}
+
 //
 // Methods
 //
@@ -73,21 +118,40 @@ BOOL	LLPanelFace::postBuild()
 {
 	childSetCommitCallback("combobox shininess",&LLPanelFace::onCommitShiny,this);
 	childSetCommitCallback("combobox bumpiness",&LLPanelFace::onCommitBump,this);
+	childSetCommitCallback("combobox alphamode",&LLPanelFace::onCommitAlphaMode,this);
 	childSetCommitCallback("TexScaleU",&LLPanelFace::onCommitTextureInfo, this);
-	childSetCommitCallback("checkbox flip s",&LLPanelFace::onCommitTextureInfo, this);
 	childSetCommitCallback("TexScaleV",&LLPanelFace::onCommitTextureInfo, this);
-	childSetCommitCallback("checkbox flip t",&LLPanelFace::onCommitTextureInfo, this);
 	childSetCommitCallback("TexRot",&LLPanelFace::onCommitTextureInfo, this);
-	childSetAction("button apply",&LLPanelFace::onClickApply,this);
+	childSetCommitCallback("rptctrl",&LLPanelFace::onCommitRepeatsPerMeter, this);
 	childSetCommitCallback("checkbox planar align",&LLPanelFace::onCommitPlanarAlign, this);
 	childSetCommitCallback("TexOffsetU",LLPanelFace::onCommitTextureInfo, this);
 	childSetCommitCallback("TexOffsetV",LLPanelFace::onCommitTextureInfo, this);
+
+	childSetCommitCallback("bumpyScaleU",&LLPanelFace::onCommitMaterialBumpyScaleX, this);
+	childSetCommitCallback("bumpyScaleV",&LLPanelFace::onCommitMaterialBumpyScaleY, this);
+	childSetCommitCallback("bumpyRot",&LLPanelFace::onCommitMaterialBumpyRot, this);
+	childSetCommitCallback("bumpyOffsetU",&LLPanelFace::onCommitMaterialBumpyOffsetX, this);
+	childSetCommitCallback("bumpyOffsetV",&LLPanelFace::onCommitMaterialBumpyOffsetY, this);
+	childSetCommitCallback("shinyScaleU",&LLPanelFace::onCommitMaterialShinyScaleX, this);
+	childSetCommitCallback("shinyScaleV",&LLPanelFace::onCommitMaterialShinyScaleY, this);
+	childSetCommitCallback("shinyRot",&LLPanelFace::onCommitMaterialShinyRot, this);
+	childSetCommitCallback("shinyOffsetU",&LLPanelFace::onCommitMaterialShinyOffsetX, this);
+	childSetCommitCallback("shinyOffsetV",&LLPanelFace::onCommitMaterialShinyOffsetY, this);
+	childSetCommitCallback("glossiness",&LLPanelFace::onCommitMaterialGloss, this);
+	childSetCommitCallback("environment",&LLPanelFace::onCommitMaterialEnv, this);
+	childSetCommitCallback("maskcutoff",&LLPanelFace::onCommitMaterialMaskCutoff, this);
+
 	childSetAction("button align",&LLPanelFace::onClickAutoFix,this);
 
 	LLTextureCtrl*	mTextureCtrl;
+	LLTextureCtrl*	mShinyTextureCtrl;
+	LLTextureCtrl*	mBumpyTextureCtrl;
 	LLColorSwatchCtrl*	mColorSwatch;
+	LLColorSwatchCtrl*	mShinyColorSwatch;
 
 	LLComboBox*		mComboTexGen;
+	LLComboBox*		mComboMatMedia;
+	LLComboBox*		mComboMatType;
 
 	LLCheckBoxCtrl	*mCheckFullbright;
 	
@@ -97,6 +161,7 @@ BOOL	LLPanelFace::postBuild()
 	LLSpinCtrl*     mCtrlGlow;
 
 	setMouseOpaque(FALSE);
+
 	mTextureCtrl = getChild<LLTextureCtrl>("texture control");
 	if(mTextureCtrl)
 	{
@@ -106,12 +171,49 @@ BOOL	LLPanelFace::postBuild()
 		mTextureCtrl->setOnSelectCallback( boost::bind(&LLPanelFace::onSelectTexture, this, _2) );
 		mTextureCtrl->setDragCallback(boost::bind(&LLPanelFace::onDragTexture, this, _2));
 		mTextureCtrl->setOnTextureSelectedCallback(boost::bind(&LLPanelFace::onTextureSelectionChanged, this, _1));
+		mTextureCtrl->setOnCloseCallback( boost::bind(&LLPanelFace::onCloseTexturePicker, this, _2) );
+
 		mTextureCtrl->setFollowsTop();
 		mTextureCtrl->setFollowsLeft();
 		mTextureCtrl->setImmediateFilterPermMask(PERM_NONE);
 		mTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER);
 	}
 
+	mShinyTextureCtrl = getChild<LLTextureCtrl>("shinytexture control");
+	if(mShinyTextureCtrl)
+	{
+		mShinyTextureCtrl->setDefaultImageAssetID(LLUUID( gSavedSettings.getString( "DefaultObjectSpecularTexture" )));
+		mShinyTextureCtrl->setCommitCallback( boost::bind(&LLPanelFace::onCommitSpecularTexture, this, _2) );
+		mShinyTextureCtrl->setOnCancelCallback( boost::bind(&LLPanelFace::onCancelSpecularTexture, this, _2) );
+		mShinyTextureCtrl->setOnSelectCallback( boost::bind(&LLPanelFace::onSelectSpecularTexture, this, _2) );
+		mShinyTextureCtrl->setOnCloseCallback( boost::bind(&LLPanelFace::onCloseTexturePicker, this, _2) );
+		
+		mShinyTextureCtrl->setDragCallback(boost::bind(&LLPanelFace::onDragTexture, this, _2));
+		mShinyTextureCtrl->setOnTextureSelectedCallback(boost::bind(&LLPanelFace::onTextureSelectionChanged, this, _1));
+		mShinyTextureCtrl->setFollowsTop();
+		mShinyTextureCtrl->setFollowsLeft();
+		mShinyTextureCtrl->setImmediateFilterPermMask(PERM_NONE);
+		mShinyTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER);
+	}
+
+	mBumpyTextureCtrl = getChild<LLTextureCtrl>("bumpytexture control");
+	if(mBumpyTextureCtrl)
+	{
+		mBumpyTextureCtrl->setDefaultImageAssetID(LLUUID( gSavedSettings.getString( "DefaultObjectNormalTexture" )));
+		mBumpyTextureCtrl->setBlankImageAssetID(LLUUID( gSavedSettings.getString( "DefaultBlankNormalTexture" )));
+		mBumpyTextureCtrl->setCommitCallback( boost::bind(&LLPanelFace::onCommitNormalTexture, this, _2) );
+		mBumpyTextureCtrl->setOnCancelCallback( boost::bind(&LLPanelFace::onCancelNormalTexture, this, _2) );
+		mBumpyTextureCtrl->setOnSelectCallback( boost::bind(&LLPanelFace::onSelectNormalTexture, this, _2) );
+		mBumpyTextureCtrl->setOnCloseCallback( boost::bind(&LLPanelFace::onCloseTexturePicker, this, _2) );
+
+		mBumpyTextureCtrl->setDragCallback(boost::bind(&LLPanelFace::onDragTexture, this, _2));
+		mBumpyTextureCtrl->setOnTextureSelectedCallback(boost::bind(&LLPanelFace::onTextureSelectionChanged, this, _1));
+		mBumpyTextureCtrl->setFollowsTop();
+		mBumpyTextureCtrl->setFollowsLeft();
+		mBumpyTextureCtrl->setImmediateFilterPermMask(PERM_NONE);
+		mBumpyTextureCtrl->setDnDFilterPermMask(PERM_COPY | PERM_TRANSFER);
+	}
+
 	mColorSwatch = getChild<LLColorSwatchCtrl>("colorswatch");
 	if(mColorSwatch)
 	{
@@ -123,6 +225,15 @@ BOOL	LLPanelFace::postBuild()
 		mColorSwatch->setCanApplyImmediately(TRUE);
 	}
 
+	mShinyColorSwatch = getChild<LLColorSwatchCtrl>("shinycolorswatch");
+	if(mShinyColorSwatch)
+	{
+		mShinyColorSwatch->setCommitCallback(boost::bind(&LLPanelFace::onCommitShinyColor, this, _2));
+		mShinyColorSwatch->setFollowsTop();
+		mShinyColorSwatch->setFollowsLeft();
+		mShinyColorSwatch->setCanApplyImmediately(TRUE);
+	}
+
 	mLabelColorTransp = getChild<LLTextBox>("color trans");
 	if(mLabelColorTransp)
 	{
@@ -152,6 +263,20 @@ BOOL	LLPanelFace::postBuild()
 		mComboTexGen->setFollows(FOLLOWS_LEFT | FOLLOWS_TOP);	
 	}
 
+	mComboMatMedia = getChild<LLComboBox>("combobox matmedia");
+	if(mComboMatMedia)
+	{
+		mComboMatMedia->setCommitCallback(LLPanelFace::onCommitMaterialsMedia,this);
+		mComboMatMedia->selectNthItem(MATMEDIA_MATERIAL);
+	}
+
+	mComboMatType = getChild<LLComboBox>("combobox mattype");
+	if(mComboMatType)
+	{
+		mComboMatType->setCommitCallback(LLPanelFace::onCommitMaterialType, this);
+		mComboMatType->selectNthItem(MATTYPE_DIFFUSE);
+	}
+
 	mCtrlGlow = getChild<LLSpinCtrl>("glow");
 	if(mCtrlGlow)
 	{
@@ -165,8 +290,10 @@ BOOL	LLPanelFace::postBuild()
 }
 
 LLPanelFace::LLPanelFace()
-:	LLPanel()
+:	LLPanel(),
+	mIsAlpha(false)
 {
+	USE_TEXTURE = LLTrans::getString("use_texture");
 }
 
 
@@ -193,12 +320,32 @@ void LLPanelFace::sendTexture()
 	}
 }
 
-void LLPanelFace::sendBump()
+void LLPanelFace::sendBump(U32 bumpiness)
 {	
-	LLComboBox*	mComboBumpiness = getChild<LLComboBox>("combobox bumpiness");
-	if(!mComboBumpiness)return;
-	U8 bump = (U8) mComboBumpiness->getCurrentIndex() & TEM_BUMP_MASK;
-	LLSelectMgr::getInstance()->selectionSetBumpmap( bump );
+	LLTextureCtrl* bumpytexture_ctrl = getChild<LLTextureCtrl>("bumpytexture control");
+	if (bumpiness < BUMPY_TEXTURE)
+	{
+		LL_DEBUGS("Materials") << "clearing bumptexture control" << LL_ENDL;	
+		bumpytexture_ctrl->clear();
+		bumpytexture_ctrl->setImageAssetID(LLUUID());		
+	}
+
+	updateBumpyControls(bumpiness == BUMPY_TEXTURE, true);
+
+	LLUUID current_normal_map = bumpytexture_ctrl->getImageAssetID();
+
+	U8 bump = (U8) bumpiness & TEM_BUMP_MASK;
+
+	// Clear legacy bump to None when using an actual normal map
+	//
+	if (!current_normal_map.isNull())
+		bump = 0;
+
+	// Set the normal map or reset it to null as appropriate
+	//
+	LLSelectedTEMaterial::setNormalID(this, current_normal_map);
+
+	LLSelectMgr::getInstance()->selectionSetBumpmap( bump );	
 }
 
 void LLPanelFace::sendTexGen()
@@ -209,12 +356,28 @@ void LLPanelFace::sendTexGen()
 	LLSelectMgr::getInstance()->selectionSetTexGen( tex_gen );
 }
 
-void LLPanelFace::sendShiny()
+void LLPanelFace::sendShiny(U32 shininess)
 {
-	LLComboBox*	mComboShininess = getChild<LLComboBox>("combobox shininess");
-	if(!mComboShininess)return;
-	U8 shiny = (U8) mComboShininess->getCurrentIndex() & TEM_SHINY_MASK;
+	LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>("shinytexture control");
+
+	if (shininess < SHINY_TEXTURE)
+	{		
+		texture_ctrl->clear();
+		texture_ctrl->setImageAssetID(LLUUID());		
+	}
+
+	LLUUID specmap = getCurrentSpecularMap();
+
+	U8 shiny = (U8) shininess & TEM_SHINY_MASK;
+	if (!specmap.isNull())
+		shiny = 0;
+
+	LLSelectedTEMaterial::setSpecularID(this, specmap);
+
 	LLSelectMgr::getInstance()->selectionSetShiny( shiny );
+
+	updateShinyControls(!specmap.isNull(), true);
+	
 }
 
 void LLPanelFace::sendFullbright()
@@ -268,22 +431,16 @@ struct LLPanelFaceSetTEFunctor : public LLSelectedTEFunctor
 		LLSpinCtrl*	ctrlTexOffsetS = mPanel->getChild<LLSpinCtrl>("TexOffsetU");
 		LLSpinCtrl*	ctrlTexOffsetT = mPanel->getChild<LLSpinCtrl>("TexOffsetV");
 		LLSpinCtrl*	ctrlTexRotation = mPanel->getChild<LLSpinCtrl>("TexRot");
-		LLCheckBoxCtrl*	checkFlipScaleS = mPanel->getChild<LLCheckBoxCtrl>("checkbox flip s");
-		LLCheckBoxCtrl*	checkFlipScaleT = mPanel->getChild<LLCheckBoxCtrl>("checkbox flip t");
 		LLComboBox*		comboTexGen = mPanel->getChild<LLComboBox>("combobox texgen");
 		llassert(comboTexGen);
 		llassert(object);
 
 		if (ctrlTexScaleS)
 		{
-			valid = !ctrlTexScaleS->getTentative() || !checkFlipScaleS->getTentative();
+			valid = !ctrlTexScaleS->getTentative(); // || !checkFlipScaleS->getTentative();
 			if (valid)
 			{
 				value = ctrlTexScaleS->get();
-				if( checkFlipScaleS->get() )
-				{
-					value = -value;
-				}
 				if (comboTexGen &&
 				    comboTexGen->getCurrentIndex() == 1)
 				{
@@ -295,14 +452,14 @@ struct LLPanelFaceSetTEFunctor : public LLSelectedTEFunctor
 
 		if (ctrlTexScaleT)
 		{
-			valid = !ctrlTexScaleT->getTentative() || !checkFlipScaleT->getTentative();
+			valid = !ctrlTexScaleT->getTentative(); // || !checkFlipScaleT->getTentative();
 			if (valid)
 			{
 				value = ctrlTexScaleT->get();
-				if( checkFlipScaleT->get() )
-				{
-					value = -value;
-				}
+				//if( checkFlipScaleT->get() )
+				//{
+				//	value = -value;
+				//}
 				if (comboTexGen &&
 				    comboTexGen->getCurrentIndex() == 1)
 				{
@@ -458,16 +615,9 @@ void LLPanelFace::sendTextureInfo()
 {
 	if ((bool)childGetValue("checkbox planar align").asBoolean())
 	{
-		struct f1 : public LLSelectedTEGetFunctor<LLFace *>
-		{
-			LLFace* get(LLViewerObject* object, S32 te)
-			{
-				return (object->mDrawable) ? object->mDrawable->getFace(te): NULL;
-			}
-		} get_last_face_func;
-		LLFace* last_face;
-		LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_last_face_func, last_face);
-
+		LLFace* last_face = NULL;
+		bool identical_face =false;
+		LLSelectedTE::getFace(last_face, identical_face);		
 		LLPanelFaceSetAlignedTEFunctor setfunc(this, last_face);
 		LLSelectMgr::getInstance()->getSelection()->applyToTEs(&setfunc);
 	}
@@ -483,6 +633,11 @@ void LLPanelFace::sendTextureInfo()
 
 void LLPanelFace::getState()
 {
+	updateUI();
+}
+
+void LLPanelFace::updateUI()
+{ //set state of UI to match state of texture entry(ies)  (calls setEnabled, setValue, etc, but NOT setVisible)
 	LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
 
 	if( objectp
@@ -492,409 +647,727 @@ void LLPanelFace::getState()
 		BOOL editable = objectp->permModify() && !objectp->isPermanentEnforced();
 
 		// only turn on auto-adjust button if there is a media renderer and the media is loaded
-		getChildView("textbox autofix")->setEnabled(editable);
 		getChildView("button align")->setEnabled(editable);
+
+		LLComboBox* combobox_matmedia = getChild<LLComboBox>("combobox matmedia");
+		if (combobox_matmedia)
+		{
+			if (combobox_matmedia->getCurrentIndex() < MATMEDIA_MATERIAL)
+			{
+				combobox_matmedia->selectNthItem(MATMEDIA_MATERIAL);
+			}
+		}
+		else
+		{
+			llwarns << "failed getChild for 'combobox matmedia'" << llendl;
+		}
+		getChildView("combobox matmedia")->setEnabled(editable);
+
+		LLComboBox* combobox_mattype = getChild<LLComboBox>("combobox mattype");
+		if (combobox_mattype)
+		{
+			if (combobox_mattype->getCurrentIndex() < MATTYPE_DIFFUSE)
+			{
+				combobox_mattype->selectNthItem(MATTYPE_DIFFUSE);
+			}
+		}
+		else
+		{
+			LL_WARNS("Materials") << "failed getChild for 'combobox mattype'" << LL_ENDL;
+		}
+		getChildView("combobox mattype")->setEnabled(editable);
+
+		updateVisibility();
+
+		bool identical				= true;	// true because it is anded below
+      bool identical_diffuse	= false;
+      bool identical_norm		= false;
+      bool identical_spec		= false;
+        
+		LLTextureCtrl*	texture_ctrl		= getChild<LLTextureCtrl>("texture control");
+		LLTextureCtrl*	shinytexture_ctrl = getChild<LLTextureCtrl>("shinytexture control");
+		LLTextureCtrl*	bumpytexture_ctrl = getChild<LLTextureCtrl>("bumpytexture control");
 		
-		//if ( LLMediaEngine::getInstance()->getMediaRenderer () )
-		//	if ( LLMediaEngine::getInstance()->getMediaRenderer ()->isLoaded () )
-		//	{	
-		//		
-		//		//mLabelTexAutoFix->setEnabled ( editable );
-		//		
-		//		//mBtnAutoFix->setEnabled ( editable );
-		//	}
-		getChildView("button apply")->setEnabled(editable);
-
-		bool identical;
-		LLTextureCtrl*	texture_ctrl = getChild<LLTextureCtrl>("texture control");
+		LLUUID id;
+		LLUUID normmap_id;
+		LLUUID specmap_id;
+
+		// Color swatch
+		{
+			getChildView("color label")->setEnabled(editable);
+		}
+		LLColorSwatchCtrl*	mColorSwatch = getChild<LLColorSwatchCtrl>("colorswatch");
+
+		LLColor4 color					= LLColor4::white;
+		bool		identical_color	= false;
+
+		if(mColorSwatch)
+		{
+			LLSelectedTE::getColor(color, identical_color);
+
+			mColorSwatch->setOriginal(color);
+			mColorSwatch->set(color, TRUE);
+
+			mColorSwatch->setValid(editable);
+			mColorSwatch->setEnabled( editable );
+			mColorSwatch->setCanApplyImmediately( editable );
+		}
+
+		// Color transparency
+		getChildView("color trans")->setEnabled(editable);
+
+		F32 transparency = (1.f - color.mV[VALPHA]) * 100.f;
+		getChild<LLUICtrl>("ColorTrans")->setValue(editable ? transparency : 0);
+		getChildView("ColorTrans")->setEnabled(editable);
+
+		// Specular map
+		LLSelectedTEMaterial::getSpecularID(specmap_id, identical_spec);
 		
-		// Texture
+		U8 shiny = 0;
+		bool identical_shiny = false;
+
+		// Shiny
+		LLSelectedTE::getShiny(shiny, identical_shiny);
+		identical = identical && identical_shiny;
+
+		shiny = specmap_id.isNull() ? shiny : SHINY_TEXTURE;
+
+		LLCtrlSelectionInterface* combobox_shininess = childGetSelectionInterface("combobox shininess");
+		if (combobox_shininess)
 		{
-			LLUUID id;
-			struct f1 : public LLSelectedTEGetFunctor<LLUUID>
+			combobox_shininess->selectNthItem((S32)shiny);
+		}
+
+		getChildView("label shininess")->setEnabled(editable);
+		getChildView("combobox shininess")->setEnabled(editable);
+
+		getChildView("label glossiness")->setEnabled(editable);			
+		getChildView("glossiness")->setEnabled(editable);
+
+		getChildView("label environment")->setEnabled(editable);
+		getChildView("environment")->setEnabled(editable);
+		getChildView("label shinycolor")->setEnabled(editable);
+
+		getChild<LLUICtrl>("combobox shininess")->setTentative(!identical_spec);
+		getChild<LLUICtrl>("glossiness")->setTentative(!identical_spec);
+		getChild<LLUICtrl>("environment")->setTentative(!identical_spec);			
+		getChild<LLUICtrl>("shinycolorswatch")->setTentative(!identical_spec);
+
+		LLColorSwatchCtrl*	mShinyColorSwatch = getChild<LLColorSwatchCtrl>("shinycolorswatch");
+		if(mShinyColorSwatch)
+		{
+			mShinyColorSwatch->setValid(editable);
+			mShinyColorSwatch->setEnabled( editable );
+			mShinyColorSwatch->setCanApplyImmediately( editable );
+		}
+
+		U8 bumpy = 0;
+		// Bumpy
+		{		
+			bool identical_bumpy = false;
+			LLSelectedTE::getBumpmap(bumpy,identical_bumpy);
+
+			LLUUID norm_map_id = getCurrentNormalMap();
+			LLCtrlSelectionInterface* combobox_bumpiness = childGetSelectionInterface("combobox bumpiness");
+
+			bumpy = norm_map_id.isNull() ? bumpy : BUMPY_TEXTURE;
+
+			if (combobox_bumpiness)
 			{
-				LLUUID get(LLViewerObject* object, S32 te_index)
-				{
-					LLUUID id;
-					
-					LLViewerTexture* image = object->getTEImage(te_index);
-					if (image) id = image->getID();
-					
-					if (!id.isNull() && LLViewerMedia::textureHasMedia(id))
-					{
-						LLTextureEntry *te = object->getTE(te_index);
-						if (te)
-						{
-							LLViewerTexture* tex = te->getID().notNull() ? gTextureList.findImage(te->getID()) : NULL ;
-							if(!tex)
-							{
-								tex = LLViewerFetchedTexture::sDefaultImagep;
-							}
-							if (tex)
-							{
-								id = tex->getID();
-							}
-						}
-					}
-					return id;
-				}
-			} func;
-			identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, id );
+				combobox_bumpiness->selectNthItem((S32)bumpy);
+			}
+			else
+			{
+				llwarns << "failed childGetSelectionInterface for 'combobox bumpiness'" << llendl;
+			}
+
+			getChildView("combobox bumpiness")->setEnabled(editable);
+			getChild<LLUICtrl>("combobox bumpiness")->setTentative(!identical_bumpy);
+			getChildView("label bumpiness")->setEnabled(editable);
+		}
+
+		// Texture
+		{
+			LLSelectedTE::getTexId(id,identical_diffuse);
+
+			// Normal map
+			LLSelectedTEMaterial::getNormalID(normmap_id, identical_norm);
+
+			mIsAlpha = FALSE;
+			LLGLenum image_format = GL_RGB;
+			bool identical_image_format = false;
+			LLSelectedTE::getImageFormat(image_format, identical_image_format);
+            
+         mIsAlpha = FALSE;
+         switch (image_format)
+         {
+               case GL_RGBA:
+               case GL_ALPHA:
+               {
+                  mIsAlpha = TRUE;
+               }
+               break;
+
+               case GL_RGB: break;
+               default:
+               {
+                  llwarns << "Unexpected tex format in LLPanelFace...resorting to no alpha" << llendl;
+               }
+               break;
+         }
 
 			if(LLViewerMedia::textureHasMedia(id))
 			{
-				getChildView("textbox autofix")->setEnabled(editable);
 				getChildView("button align")->setEnabled(editable);
 			}
 			
-			if (identical)
+			// Diffuse Alpha Mode
+
+			// Init to the default that is appropriate for the alpha content of the asset
+			//
+			U8 alpha_mode = mIsAlpha ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
+
+			bool identical_alpha_mode = false;
+
+			// See if that's been overridden by a material setting for same...
+			//
+			LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(alpha_mode, identical_alpha_mode, mIsAlpha);
+
+			LLCtrlSelectionInterface* combobox_alphamode = childGetSelectionInterface("combobox alphamode");
+			if (combobox_alphamode)
+			{
+				//it is invalid to have any alpha mode other than blend if transparency is greater than zero ... 
+				// Want masking? Want emissive? Tough! You get BLEND!
+				alpha_mode = (transparency > 0.f) ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : alpha_mode;
+
+				// ... unless there is no alpha channel in the texture, in which case alpha mode MUST be none
+				alpha_mode = mIsAlpha ? alpha_mode : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
+
+				combobox_alphamode->selectNthItem(alpha_mode);
+			}
+			else
+			{
+				llwarns << "failed childGetSelectionInterface for 'combobox alphamode'" << llendl;
+			}
+
+			updateAlphaControls();
+			
+			if(texture_ctrl)
 			{
-				// All selected have the same texture
-				if(texture_ctrl)
+				if (identical_diffuse)
+				{
+					texture_ctrl->setTentative( FALSE );
+					texture_ctrl->setEnabled( editable );
+					texture_ctrl->setImageAssetID( id );
+					getChildView("combobox alphamode")->setEnabled(editable && mIsAlpha && transparency <= 0.f);
+					getChildView("label alphamode")->setEnabled(editable && mIsAlpha);
+					getChildView("maskcutoff")->setEnabled(editable && mIsAlpha);
+					getChildView("label maskcutoff")->setEnabled(editable && mIsAlpha);
+				}
+				else if (id.isNull())
 				{
+					// None selected
 					texture_ctrl->setTentative( FALSE );
+					texture_ctrl->setEnabled( FALSE );
+					texture_ctrl->setImageAssetID( LLUUID::null );
+					getChildView("combobox alphamode")->setEnabled( FALSE );
+					getChildView("label alphamode")->setEnabled( FALSE );
+					getChildView("maskcutoff")->setEnabled( FALSE);
+					getChildView("label maskcutoff")->setEnabled( FALSE );
+				}
+				else
+				{
+					// Tentative: multiple selected with different textures
+					texture_ctrl->setTentative( TRUE );
 					texture_ctrl->setEnabled( editable );
 					texture_ctrl->setImageAssetID( id );
+					getChildView("combobox alphamode")->setEnabled(editable && mIsAlpha && transparency <= 0.f);
+					getChildView("label alphamode")->setEnabled(editable && mIsAlpha);
+					getChildView("maskcutoff")->setEnabled(editable && mIsAlpha);
+					getChildView("label maskcutoff")->setEnabled(editable && mIsAlpha);
 				}
 			}
-			else
-			{
-				if(texture_ctrl)
+            
+         if (shinytexture_ctrl)
+         {
+				if (identical_spec && (shiny == SHINY_TEXTURE))
 				{
-					if( id.isNull() )
-					{
-						// None selected
-						texture_ctrl->setTentative( FALSE );
-						texture_ctrl->setEnabled( FALSE );
-						texture_ctrl->setImageAssetID( LLUUID::null );
-					}
-					else
-					{
-						// Tentative: multiple selected with different textures
-						texture_ctrl->setTentative( TRUE );
-						texture_ctrl->setEnabled( editable );
-						texture_ctrl->setImageAssetID( id );
-					}
+					shinytexture_ctrl->setTentative( FALSE );
+					shinytexture_ctrl->setEnabled( editable );
+					shinytexture_ctrl->setImageAssetID( specmap_id );
+            }
+            else if (specmap_id.isNull())
+				{
+               shinytexture_ctrl->setTentative( FALSE );
+               shinytexture_ctrl->setEnabled( editable );
+					shinytexture_ctrl->setImageAssetID( LLUUID::null );
+            }
+            else
+            {
+					shinytexture_ctrl->setTentative( TRUE );
+					shinytexture_ctrl->setEnabled( editable );
+					shinytexture_ctrl->setImageAssetID( specmap_id );
+				}
+         }
+
+         if (bumpytexture_ctrl)
+         {
+				if (identical_norm && (bumpy == BUMPY_TEXTURE))
+				{
+					bumpytexture_ctrl->setTentative( FALSE );
+					bumpytexture_ctrl->setEnabled( editable );
+					bumpytexture_ctrl->setImageAssetID( normmap_id );
+				}
+				else if (normmap_id.isNull())
+				{
+					bumpytexture_ctrl->setTentative( FALSE );
+					bumpytexture_ctrl->setEnabled( editable );
+					bumpytexture_ctrl->setImageAssetID( LLUUID::null );
+				}
+            else
+            {
+					bumpytexture_ctrl->setTentative( TRUE );
+					bumpytexture_ctrl->setEnabled( editable );
+					bumpytexture_ctrl->setImageAssetID( normmap_id );
 				}
 			}
 		}
-
 		
 		// planar align
 		bool align_planar = false;
 		bool identical_planar_aligned = false;
-		bool is_planar = false;
 		{
 			LLCheckBoxCtrl*	cb_planar_align = getChild<LLCheckBoxCtrl>("checkbox planar align");
 			align_planar = (cb_planar_align && cb_planar_align->get());
-			struct f1 : public LLSelectedTEGetFunctor<bool>
-			{
-				bool get(LLViewerObject* object, S32 face)
-				{
-					return (object->getTE(face)->getTexGen() == LLTextureEntry::TEX_GEN_PLANAR);
-				}
-			} func;
-
-			bool texgens_identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, is_planar );
-			bool enabled = (editable && texgens_identical && is_planar);
+			
+			bool enabled = (editable && isIdenticalPlanarTexgen());
 			childSetValue("checkbox planar align", align_planar && enabled);
 			childSetEnabled("checkbox planar align", enabled);
 
 			if (align_planar && enabled)
 			{
-				struct f2 : public LLSelectedTEGetFunctor<LLFace *>
-				{
-					LLFace* get(LLViewerObject* object, S32 te)
-					{
-						return (object->mDrawable) ? object->mDrawable->getFace(te): NULL;
-					}
-				} get_te_face_func;
-				LLFace* last_face;
-				LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_te_face_func, last_face);
+				LLFace* last_face = NULL;
+				bool identical_face = false;
+				LLSelectedTE::getFace(last_face, identical_face);
+
 				LLPanelFaceGetIsAlignedTEFunctor get_is_aligend_func(last_face);
 				// this will determine if the texture param controls are tentative:
 				identical_planar_aligned = LLSelectMgr::getInstance()->getSelection()->applyToTEs(&get_is_aligend_func);
 			}
 		}
 		
+		// Needs to be public and before tex scale settings below to properly reflect
+		// behavior when in planar vs default texgen modes in the
+		// NORSPEC-84 et al
+		//
+		LLTextureEntry::e_texgen selected_texgen = LLTextureEntry::TEX_GEN_DEFAULT;
+		bool identical_texgen = true;		
+		bool identical_planar_texgen = false;
+
+		{	
+			LLSelectedTE::getTexGen(selected_texgen, identical_texgen);
+			identical_planar_texgen = (identical_texgen && (selected_texgen == LLTextureEntry::TEX_GEN_PLANAR));
+		}
+
 		// Texture scale
 		{
-			F32 scale_s = 1.f;
-			struct f2 : public LLSelectedTEGetFunctor<F32>
-			{
-				F32 get(LLViewerObject* object, S32 face)
-				{
-					return object->getTE(face)->mScaleS;
-				}
-			} func;
-			identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, scale_s );
+			bool identical_diff_scale_s = false;
+			bool identical_spec_scale_s = false;
+			bool identical_norm_scale_s = false;
+
 			identical = align_planar ? identical_planar_aligned : identical;
-			getChild<LLUICtrl>("TexScaleU")->setValue(editable ? llabs(scale_s) : 0);
-			getChild<LLUICtrl>("TexScaleU")->setTentative(LLSD((BOOL)(!identical)));
+
+			F32 diff_scale_s = 1.f;			
+			F32 spec_scale_s = 1.f;
+			F32 norm_scale_s = 1.f;
+
+			LLSelectedTE::getScaleS(						diff_scale_s, identical_diff_scale_s);			
+			LLSelectedTEMaterial::getSpecularRepeatX( spec_scale_s, identical_spec_scale_s);
+			LLSelectedTEMaterial::getNormalRepeatX(	norm_scale_s, identical_norm_scale_s);
+
+			diff_scale_s = editable ? diff_scale_s : 1.0f;
+			diff_scale_s *= identical_planar_texgen ? 2.0f : 1.0f;
+			
+			norm_scale_s = editable ? norm_scale_s : 1.0f;
+			norm_scale_s *= identical_planar_texgen ? 2.0f : 1.0f;
+
+			spec_scale_s = editable ? spec_scale_s : 1.0f;
+			spec_scale_s *= identical_planar_texgen ? 2.0f : 1.0f;
+
+			getChild<LLUICtrl>("TexScaleU")->setValue(diff_scale_s);
+			getChild<LLUICtrl>("shinyScaleU")->setValue(spec_scale_s);
+			getChild<LLUICtrl>("bumpyScaleU")->setValue(norm_scale_s);
+
 			getChildView("TexScaleU")->setEnabled(editable);
-			getChild<LLUICtrl>("checkbox flip s")->setValue(LLSD((BOOL)(scale_s < 0 ? TRUE : FALSE )));
-			getChild<LLUICtrl>("checkbox flip s")->setTentative(LLSD((BOOL)((!identical) ? TRUE : FALSE )));
-			getChildView("checkbox flip s")->setEnabled(editable);
+			getChildView("shinyScaleU")->setEnabled(editable && specmap_id.notNull());
+			getChildView("bumpyScaleU")->setEnabled(editable && normmap_id.notNull());
+
+			BOOL diff_scale_tentative = !(identical && identical_diff_scale_s);
+			BOOL norm_scale_tentative = !(identical && identical_norm_scale_s);
+			BOOL spec_scale_tentative = !(identical && identical_spec_scale_s);
+
+			getChild<LLUICtrl>("TexScaleU")->setTentative(  LLSD(diff_scale_tentative));			
+			getChild<LLUICtrl>("shinyScaleU")->setTentative(LLSD(spec_scale_tentative));			
+			getChild<LLUICtrl>("bumpyScaleU")->setTentative(LLSD(norm_scale_tentative));
 		}
 
 		{
-			F32 scale_t = 1.f;
-			struct f3 : public LLSelectedTEGetFunctor<F32>
-			{
-				F32 get(LLViewerObject* object, S32 face)
-				{
-					return object->getTE(face)->mScaleT;
-				}
-			} func;
-			identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, scale_t );
-			identical = align_planar ? identical_planar_aligned : identical;
+			bool identical_diff_scale_t = false;
+			bool identical_spec_scale_t = false;
+			bool identical_norm_scale_t = false;
+
+			F32 diff_scale_t = 1.f;			
+			F32 spec_scale_t = 1.f;
+			F32 norm_scale_t = 1.f;
+
+			LLSelectedTE::getScaleT(diff_scale_t, identical_diff_scale_t);
+			LLSelectedTEMaterial::getSpecularRepeatY(spec_scale_t, identical_spec_scale_t);
+			LLSelectedTEMaterial::getNormalRepeatY(norm_scale_t, identical_norm_scale_t);
+
+			diff_scale_t = editable ? diff_scale_t : 1.0f;
+			diff_scale_t *= identical_planar_texgen ? 2.0f : 1.0f;
+
+			norm_scale_t = editable ? norm_scale_t : 1.0f;
+			norm_scale_t *= identical_planar_texgen ? 2.0f : 1.0f;
+
+			spec_scale_t = editable ? spec_scale_t : 1.0f;
+			spec_scale_t *= identical_planar_texgen ? 2.0f : 1.0f;
+
+			BOOL diff_scale_tentative = !identical_diff_scale_t;
+			BOOL norm_scale_tentative = !identical_norm_scale_t;
+			BOOL spec_scale_tentative = !identical_spec_scale_t;
 
-			getChild<LLUICtrl>("TexScaleV")->setValue(llabs(editable ? llabs(scale_t) : 0));
-			getChild<LLUICtrl>("TexScaleV")->setTentative(LLSD((BOOL)(!identical)));
 			getChildView("TexScaleV")->setEnabled(editable);
-			getChild<LLUICtrl>("checkbox flip t")->setValue(LLSD((BOOL)(scale_t< 0 ? TRUE : FALSE )));
-			getChild<LLUICtrl>("checkbox flip t")->setTentative(LLSD((BOOL)((!identical) ? TRUE : FALSE )));
-			getChildView("checkbox flip t")->setEnabled(editable);
+			getChildView("shinyScaleV")->setEnabled(editable && specmap_id.notNull());
+			getChildView("bumpyScaleV")->setEnabled(editable && normmap_id.notNull());
+
+			getChild<LLUICtrl>("TexScaleV")->setValue(diff_scale_t);
+			getChild<LLUICtrl>("shinyScaleV")->setValue(norm_scale_t);
+			getChild<LLUICtrl>("bumpyScaleV")->setValue(spec_scale_t);
+
+			getChild<LLUICtrl>("TexScaleV")->setTentative(LLSD(diff_scale_tentative));
+			getChild<LLUICtrl>("shinyScaleV")->setTentative(LLSD(norm_scale_tentative));
+			getChild<LLUICtrl>("bumpyScaleV")->setTentative(LLSD(spec_scale_tentative));
 		}
 
 		// Texture offset
 		{
-			getChildView("tex offset")->setEnabled(editable);
-			F32 offset_s = 0.f;
-			struct f4 : public LLSelectedTEGetFunctor<F32>
-			{
-				F32 get(LLViewerObject* object, S32 face)
-				{
-					return object->getTE(face)->mOffsetS;
-				}
-			} func;
-			identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, offset_s );
-			identical = align_planar ? identical_planar_aligned : identical;
-			getChild<LLUICtrl>("TexOffsetU")->setValue(editable ? offset_s : 0);
-			getChild<LLUICtrl>("TexOffsetU")->setTentative(!identical);
+			bool identical_diff_offset_s = false;
+			bool identical_norm_offset_s = false;
+			bool identical_spec_offset_s = false;
+
+			F32 diff_offset_s = 0.0f;
+			F32 norm_offset_s = 0.0f;
+			F32 spec_offset_s = 0.0f;
+
+			LLSelectedTE::getOffsetS(diff_offset_s, identical_diff_offset_s);
+			LLSelectedTEMaterial::getNormalOffsetX(norm_offset_s, identical_norm_offset_s);
+			LLSelectedTEMaterial::getSpecularOffsetX(spec_offset_s, identical_spec_offset_s);
+
+			BOOL diff_offset_u_tentative = !(align_planar ? identical_planar_aligned : identical_diff_offset_s);
+			BOOL norm_offset_u_tentative = !(align_planar ? identical_planar_aligned : identical_norm_offset_s);
+			BOOL spec_offset_u_tentative = !(align_planar ? identical_planar_aligned : identical_spec_offset_s);
+
+			getChild<LLUICtrl>("TexOffsetU")->setValue(  editable ? diff_offset_s : 0.0f);
+			getChild<LLUICtrl>("bumpyOffsetU")->setValue(editable ? norm_offset_s : 0.0f);
+			getChild<LLUICtrl>("shinyOffsetU")->setValue(editable ? spec_offset_s : 0.0f);
+
+			getChild<LLUICtrl>("TexOffsetU")->setTentative(LLSD(diff_offset_u_tentative));
+			getChild<LLUICtrl>("shinyOffsetU")->setTentative(LLSD(norm_offset_u_tentative));
+			getChild<LLUICtrl>("bumpyOffsetU")->setTentative(LLSD(spec_offset_u_tentative));
+
 			getChildView("TexOffsetU")->setEnabled(editable);
+			getChildView("shinyOffsetU")->setEnabled(editable && specmap_id.notNull());
+			getChildView("bumpyOffsetU")->setEnabled(editable && normmap_id.notNull());
 		}
 
 		{
-			F32 offset_t = 0.f;
-			struct f5 : public LLSelectedTEGetFunctor<F32>
-			{
-				F32 get(LLViewerObject* object, S32 face)
-				{
-					return object->getTE(face)->mOffsetT;
-				}
-			} func;
-			identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, offset_t );
-			identical = align_planar ? identical_planar_aligned : identical;
-			getChild<LLUICtrl>("TexOffsetV")->setValue(editable ? offset_t : 0);
-			getChild<LLUICtrl>("TexOffsetV")->setTentative(!identical);
+			bool identical_diff_offset_t = false;
+			bool identical_norm_offset_t = false;
+			bool identical_spec_offset_t = false;
+
+			F32 diff_offset_t = 0.0f;
+			F32 norm_offset_t = 0.0f;
+			F32 spec_offset_t = 0.0f;
+
+			LLSelectedTE::getOffsetT(diff_offset_t, identical_diff_offset_t);
+			LLSelectedTEMaterial::getNormalOffsetY(norm_offset_t, identical_norm_offset_t);
+			LLSelectedTEMaterial::getSpecularOffsetY(spec_offset_t, identical_spec_offset_t);
+			
+			BOOL diff_offset_v_tentative = !(align_planar ? identical_planar_aligned : identical_diff_offset_t);
+			BOOL norm_offset_v_tentative = !(align_planar ? identical_planar_aligned : identical_norm_offset_t);
+			BOOL spec_offset_v_tentative = !(align_planar ? identical_planar_aligned : identical_spec_offset_t);
+
+			getChild<LLUICtrl>("TexOffsetV")->setValue(  editable ? diff_offset_t : 0.0f);
+			getChild<LLUICtrl>("bumpyOffsetV")->setValue(editable ? norm_offset_t : 0.0f);
+			getChild<LLUICtrl>("shinyOffsetV")->setValue(editable ? spec_offset_t : 0.0f);
+
+			getChild<LLUICtrl>("TexOffsetV")->setTentative(LLSD(diff_offset_v_tentative));
+			getChild<LLUICtrl>("shinyOffsetV")->setTentative(LLSD(norm_offset_v_tentative));
+			getChild<LLUICtrl>("bumpyOffsetV")->setTentative(LLSD(spec_offset_v_tentative));
+
 			getChildView("TexOffsetV")->setEnabled(editable);
+			getChildView("shinyOffsetV")->setEnabled(editable && specmap_id.notNull());
+			getChildView("bumpyOffsetV")->setEnabled(editable && normmap_id.notNull());
 		}
 
 		// Texture rotation
 		{
-			F32 rotation = 0.f;
-			struct f6 : public LLSelectedTEGetFunctor<F32>
-			{
-				F32 get(LLViewerObject* object, S32 face)
-				{
-					return object->getTE(face)->mRotation;
-				}
-			} func;
-			identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, rotation );
-			identical = align_planar ? identical_planar_aligned : identical;
-			getChild<LLUICtrl>("TexRot")->setValue(editable ? rotation * RAD_TO_DEG : 0);
-			getChild<LLUICtrl>("TexRot")->setTentative(!identical);
-			getChildView("TexRot")->setEnabled(editable);
-		}
+			bool identical_diff_rotation = false;
+			bool identical_norm_rotation = false;
+			bool identical_spec_rotation = false;
 
-		// Color swatch
-		LLColorSwatchCtrl*	mColorSwatch = getChild<LLColorSwatchCtrl>("colorswatch");
-		LLColor4 color = LLColor4::white;
-		if(mColorSwatch)
-		{
-			struct f7 : public LLSelectedTEGetFunctor<LLColor4>
-			{
-				LLColor4 get(LLViewerObject* object, S32 face)
-				{
-					return object->getTE(face)->getColor();
-				}
-			} func;
-			identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, color );
-			
-			mColorSwatch->setOriginal(color);
-			mColorSwatch->set(color, TRUE);
+			F32 diff_rotation = 0.f;
+			F32 norm_rotation = 0.f;
+			F32 spec_rotation = 0.f;
 
-			mColorSwatch->setValid(editable);
-			mColorSwatch->setEnabled( editable );
-			mColorSwatch->setCanApplyImmediately( editable );
-		}
-		// Color transparency
-		{
-			getChildView("color trans")->setEnabled(editable);
-		}
+			LLSelectedTE::getRotation(diff_rotation,identical_diff_rotation);
+			LLSelectedTEMaterial::getSpecularRotation(spec_rotation,identical_spec_rotation);
+			LLSelectedTEMaterial::getNormalRotation(norm_rotation,identical_norm_rotation);
 
-		F32 transparency = (1.f - color.mV[VALPHA]) * 100.f;
-		{
-			getChild<LLUICtrl>("ColorTrans")->setValue(editable ? transparency : 0);
-			getChildView("ColorTrans")->setEnabled(editable);
+			BOOL diff_rot_tentative = !(align_planar ? identical_planar_aligned : identical_diff_rotation);
+			BOOL norm_rot_tentative = !(align_planar ? identical_planar_aligned : identical_norm_rotation);
+			BOOL spec_rot_tentative = !(align_planar ? identical_planar_aligned : identical_spec_rotation);
+
+			F32 diff_rot_deg = diff_rotation * RAD_TO_DEG;
+			F32 norm_rot_deg = norm_rotation * RAD_TO_DEG;
+			F32 spec_rot_deg = spec_rotation * RAD_TO_DEG;
+
+			getChildView("TexRot")->setEnabled(editable);
+			getChildView("shinyRot")->setEnabled(editable && specmap_id.notNull());
+			getChildView("bumpyRot")->setEnabled(editable && normmap_id.notNull());
+
+			getChild<LLUICtrl>("TexRot")->setTentative(diff_rot_tentative);
+			getChild<LLUICtrl>("shinyRot")->setTentative(LLSD(norm_rot_tentative));
+			getChild<LLUICtrl>("bumpyRot")->setTentative(LLSD(spec_rot_tentative));
+
+			getChild<LLUICtrl>("TexRot")->setValue(  editable ? diff_rot_deg : 0.0f);			
+			getChild<LLUICtrl>("shinyRot")->setValue(editable ? spec_rot_deg : 0.0f);
+			getChild<LLUICtrl>("bumpyRot")->setValue(editable ? norm_rot_deg : 0.0f);
 		}
 
 		{
 			F32 glow = 0.f;
-			struct f8 : public LLSelectedTEGetFunctor<F32>
-			{
-				F32 get(LLViewerObject* object, S32 face)
-				{
-					return object->getTE(face)->getGlow();
-				}
-			} func;
-			identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, glow );
-
+			bool identical_glow = false;
+			LLSelectedTE::getGlow(glow,identical_glow);
 			getChild<LLUICtrl>("glow")->setValue(glow);
+			getChild<LLUICtrl>("glow")->setTentative(!identical_glow);
 			getChildView("glow")->setEnabled(editable);
-			getChild<LLUICtrl>("glow")->setTentative(!identical);
-			getChildView("glow label")->setEnabled(editable);
-
+			getChildView("glow label")->setEnabled(editable);			
 		}
 
-		// Bump
-		{
-			F32 shinyf = 0.f;
-			struct f9 : public LLSelectedTEGetFunctor<F32>
-			{
-				F32 get(LLViewerObject* object, S32 face)
-				{
-					return (F32)(object->getTE(face)->getShiny());
-				}
-			} func;
-			identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, shinyf );
-			LLCtrlSelectionInterface* combobox_shininess =
-			      childGetSelectionInterface("combobox shininess");
-			if (combobox_shininess)
+		{			
+			LLCtrlSelectionInterface* combobox_texgen = childGetSelectionInterface("combobox texgen");
+			if (combobox_texgen)
 			{
-				combobox_shininess->selectNthItem((S32)shinyf);
+				// Maps from enum to combobox entry index
+				combobox_texgen->selectNthItem(((S32)selected_texgen) >> 1);
 			}
 			else
 			{
-				llwarns << "failed childGetSelectionInterface for 'combobox shininess'" << llendl;
+				llwarns << "failed childGetSelectionInterface for 'combobox texgen'" << llendl;
 			}
-			getChildView("combobox shininess")->setEnabled(editable);
-			getChild<LLUICtrl>("combobox shininess")->setTentative(!identical);
-			getChildView("label shininess")->setEnabled(editable);
-		}
 
-		{
-			F32 bumpf = 0.f;
-			struct f10 : public LLSelectedTEGetFunctor<F32>
-			{
-				F32 get(LLViewerObject* object, S32 face)
-				{
-					return (F32)(object->getTE(face)->getBumpmap());
-				}
-			} func;
-			identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, bumpf );
-			LLCtrlSelectionInterface* combobox_bumpiness =
-			      childGetSelectionInterface("combobox bumpiness");
-			if (combobox_bumpiness)
-			{
-				combobox_bumpiness->selectNthItem((S32)bumpf);
-			}
-			else
-			{
-				llwarns << "failed childGetSelectionInterface for 'combobox bumpiness'" << llendl;
-			}
-			getChildView("combobox bumpiness")->setEnabled(editable);
-			getChild<LLUICtrl>("combobox bumpiness")->setTentative(!identical);
-			getChildView("label bumpiness")->setEnabled(editable);
-		}
-
-		{
-			F32 genf = 0.f;
-			struct f11 : public LLSelectedTEGetFunctor<F32>
-			{
-				F32 get(LLViewerObject* object, S32 face)
-				{
-					return (F32)(object->getTE(face)->getTexGen());
-				}
-			} func;
-			identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, genf );
-			S32 selected_texgen = ((S32) genf) >> TEM_TEX_GEN_SHIFT;
-			LLCtrlSelectionInterface* combobox_texgen =
-			      childGetSelectionInterface("combobox texgen");
-			if (combobox_texgen)
-			{
-				combobox_texgen->selectNthItem(selected_texgen);
-			}
-			else
-			{
-				llwarns << "failed childGetSelectionInterface for 'combobox texgen'" << llendl;
-			}
 			getChildView("combobox texgen")->setEnabled(editable);
 			getChild<LLUICtrl>("combobox texgen")->setTentative(!identical);
 			getChildView("tex gen")->setEnabled(editable);
 
-			if (selected_texgen == 1)
+			if (selected_texgen == LLTextureEntry::TEX_GEN_PLANAR)
 			{
-				getChild<LLUICtrl>("TexScaleU")->setValue(2.0f * getChild<LLUICtrl>("TexScaleU")->getValue().asReal() );
-				getChild<LLUICtrl>("TexScaleV")->setValue(2.0f * getChild<LLUICtrl>("TexScaleV")->getValue().asReal() );
-
 				// EXP-1507 (change label based on the mapping mode)
 				getChild<LLUICtrl>("rpt")->setValue(getString("string repeats per meter"));
 			}
 			else
-			if (selected_texgen == 0)  // FIXME: should not be magic numbers
+			if (selected_texgen == LLTextureEntry::TEX_GEN_DEFAULT)
 			{
 				getChild<LLUICtrl>("rpt")->setValue(getString("string repeats per face"));
 			}
 		}
 
 		{
-			F32 fullbrightf = 0.f;
-			struct f12 : public LLSelectedTEGetFunctor<F32>
-			{
-				F32 get(LLViewerObject* object, S32 face)
-				{
-					return (F32)(object->getTE(face)->getFullbright());
-				}
-			} func;
-			identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, fullbrightf );
+			U8 fullbright_flag = 0;
+			bool identical_fullbright = false;
+			
+			LLSelectedTE::getFullbright(fullbright_flag,identical_fullbright);
 
-			getChild<LLUICtrl>("checkbox fullbright")->setValue((S32)fullbrightf);
+			getChild<LLUICtrl>("checkbox fullbright")->setValue((S32)(fullbright_flag != 0));
 			getChildView("checkbox fullbright")->setEnabled(editable);
-			getChild<LLUICtrl>("checkbox fullbright")->setTentative(!identical);
+			getChild<LLUICtrl>("checkbox fullbright")->setTentative(!identical_fullbright);
 		}
 		
-		// Repeats per meter label
+		// Repeats per meter
 		{
-			getChildView("rpt")->setEnabled(editable);
+			F32 repeats_diff = 1.f;
+			F32 repeats_norm = 1.f;
+			F32 repeats_spec = 1.f;
+
+			bool identical_diff_repeats = false;
+			bool identical_norm_repeats = false;
+			bool identical_spec_repeats = false;
+
+			LLSelectedTE::getMaxDiffuseRepeats(repeats_diff, identical_diff_repeats);
+			LLSelectedTEMaterial::getMaxNormalRepeats(repeats_norm, identical_norm_repeats);
+			LLSelectedTEMaterial::getMaxSpecularRepeats(repeats_spec, identical_spec_repeats);			
+
+			LLComboBox*	mComboTexGen = getChild<LLComboBox>("combobox texgen");
+			if (mComboTexGen)
+			{
+				S32 index = mComboTexGen ? mComboTexGen->getCurrentIndex() : 0;
+				BOOL enabled = editable && (index != 1);
+				BOOL identical_repeats = true;
+				F32  repeats = 1.0f;
+
+				U32 material_type = (combobox_matmedia->getCurrentIndex() == MATMEDIA_MATERIAL) ? combobox_mattype->getCurrentIndex() : MATTYPE_DIFFUSE;
+				switch (material_type)
+				{
+					default:
+					case MATTYPE_DIFFUSE:
+					{
+						enabled = editable && !id.isNull();
+						identical_repeats = identical_diff_repeats;
+						repeats = repeats_diff;
+					}
+					break;
+
+					case MATTYPE_SPECULAR:
+					{
+						enabled = (editable && ((shiny == SHINY_TEXTURE) && !specmap_id.isNull()));
+						identical_repeats = identical_spec_repeats;
+						repeats = repeats_spec;
+					}
+					break;
+
+					case MATTYPE_NORMAL:
+					{
+						enabled = (editable && ((bumpy == BUMPY_TEXTURE) && !normmap_id.isNull()));
+						identical_repeats = identical_norm_repeats;
+						repeats = repeats_norm;
+					}
+					break;
+				}
+
+				BOOL repeats_tentative = !identical_repeats;
+
+				getChildView("rptctrl")->setEnabled(identical_planar_texgen ? FALSE : enabled);
+				getChild<LLUICtrl>("rptctrl")->setValue(editable ? repeats : 1.0f);
+				getChild<LLUICtrl>("rptctrl")->setTentative(LLSD(repeats_tentative));
+			}
 		}
 
-		// Repeats per meter
+		// Materials
 		{
-			F32 repeats = 1.f;
-			struct f13 : public LLSelectedTEGetFunctor<F32>
+			LLMaterialPtr material;
+			LLSelectedTEMaterial::getCurrent(material, identical);
+
+			if (material && editable)
 			{
-				F32 get(LLViewerObject* object, S32 face)
+				LL_DEBUGS("Materials: OnMatererialsLoaded:") << material->asLLSD() << LL_ENDL;
+
+				// Alpha
+				LLCtrlSelectionInterface* combobox_alphamode =
+					childGetSelectionInterface("combobox alphamode");
+				if (combobox_alphamode)
 				{
-					U32 s_axis = VX;
-					U32 t_axis = VY;
-					// BUG: Only repeats along S axis
-					// BUG: Only works for boxes.
-					LLPrimitive::getTESTAxes(face, &s_axis, &t_axis);
-					return object->getTE(face)->mScaleS / object->getScale().mV[s_axis];
+					U32 alpha_mode = material->getDiffuseAlphaMode();
+
+					if (transparency > 0.f)
+					{ //it is invalid to have any alpha mode other than blend if transparency is greater than zero ... 
+						alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND;
+					}
+
+					if (!mIsAlpha)
+					{ // ... unless there is no alpha channel in the texture, in which case alpha mode MUST ebe none
+						alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
+					}
+
+					combobox_alphamode->selectNthItem(alpha_mode);
 				}
-			} func;			
-			identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, repeats );
-			
-			getChild<LLUICtrl>("rptctrl")->setValue(editable ? repeats : 0);
-			getChild<LLUICtrl>("rptctrl")->setTentative(!identical);
-			LLComboBox*	mComboTexGen = getChild<LLComboBox>("combobox texgen");
-			if (mComboTexGen)
+				else
+				{
+					llwarns << "failed childGetSelectionInterface for 'combobox alphamode'" << llendl;
+				}
+				getChild<LLUICtrl>("maskcutoff")->setValue(material->getAlphaMaskCutoff());
+				updateAlphaControls();
+
+				identical_planar_texgen = isIdenticalPlanarTexgen();
+
+				// Shiny (specular)
+				F32 offset_x, offset_y, repeat_x, repeat_y, rot;
+				LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>("shinytexture control");
+				texture_ctrl->setImageAssetID(material->getSpecularID());
+
+				if (!material->getSpecularID().isNull() && (shiny == SHINY_TEXTURE))
+				{
+					material->getSpecularOffset(offset_x,offset_y);
+					material->getSpecularRepeat(repeat_x,repeat_y);
+
+					if (identical_planar_texgen)
+					{
+						repeat_x *= 2.0f;
+						repeat_y *= 2.0f;
+					}
+
+					rot = material->getSpecularRotation();
+					getChild<LLUICtrl>("shinyScaleU")->setValue(repeat_x);
+					getChild<LLUICtrl>("shinyScaleV")->setValue(repeat_y);
+					getChild<LLUICtrl>("shinyRot")->setValue(rot*RAD_TO_DEG);
+					getChild<LLUICtrl>("shinyOffsetU")->setValue(offset_x);
+					getChild<LLUICtrl>("shinyOffsetV")->setValue(offset_y);
+					getChild<LLUICtrl>("glossiness")->setValue(material->getSpecularLightExponent());
+					getChild<LLUICtrl>("environment")->setValue(material->getEnvironmentIntensity());
+
+					updateShinyControls(!material->getSpecularID().isNull(), true);
+				}
+
+				// Assert desired colorswatch color to match material AFTER updateShinyControls
+				// to avoid getting overwritten with the default on some UI state changes.
+				//
+				if (!material->getSpecularID().isNull())
+				{
+					getChild<LLColorSwatchCtrl>("shinycolorswatch")->setOriginal(material->getSpecularLightColor());
+					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());
+
+				if (!material->getNormalID().isNull())
+				{
+					material->getNormalOffset(offset_x,offset_y);
+					material->getNormalRepeat(repeat_x,repeat_y);
+
+					if (identical_planar_texgen)
+					{
+						repeat_x *= 2.0f;
+						repeat_y *= 2.0f;
+					}
+
+					rot = material->getNormalRotation();
+					getChild<LLUICtrl>("bumpyScaleU")->setValue(repeat_x);
+					getChild<LLUICtrl>("bumpyScaleV")->setValue(repeat_y);
+					getChild<LLUICtrl>("bumpyRot")->setValue(rot*RAD_TO_DEG);
+					getChild<LLUICtrl>("bumpyOffsetU")->setValue(offset_x);
+					getChild<LLUICtrl>("bumpyOffsetV")->setValue(offset_y);
+
+					updateBumpyControls(!material->getNormalID().isNull(), true);
+				}
+			}
+			else
 			{
-				BOOL enabled = editable && (!mComboTexGen || mComboTexGen->getCurrentIndex() != 1);
-				getChildView("rptctrl")->setEnabled(enabled);
-				getChildView("button apply")->setEnabled(enabled);
+				LLSelectMgr::getInstance()->setTextureChannel(LLRender::DIFFUSE_MAP);
 			}
 		}
 
@@ -934,14 +1407,11 @@ void LLPanelFace::getState()
 		getChildView("tex gen")->setEnabled(FALSE);
 		getChildView("label shininess")->setEnabled(FALSE);
 		getChildView("label bumpiness")->setEnabled(FALSE);
-
-		getChildView("textbox autofix")->setEnabled(FALSE);
-
 		getChildView("button align")->setEnabled(FALSE);
-		getChildView("button apply")->setEnabled(FALSE);
 		//getChildView("has media")->setEnabled(FALSE);
 		//getChildView("media info set")->setEnabled(FALSE);
-		
+
+		updateVisibility();
 
 		// Set variable values for numeric expressions
 		LLCalc* calcp = LLCalc::getInstance();
@@ -958,6 +1428,7 @@ void LLPanelFace::getState()
 
 void LLPanelFace::refresh()
 {
+	LL_DEBUGS("Materials") << LL_ENDL;
 	getState();
 }
 
@@ -977,6 +1448,11 @@ void LLPanelFace::onCommitColor(const LLSD& data)
 	sendColor();
 }
 
+void LLPanelFace::onCommitShinyColor(const LLSD& data)
+{
+	LLSelectedTEMaterial::setSpecularLightColor(this, getChild<LLColorSwatchCtrl>("shinycolorswatch")->get());
+}
+
 void LLPanelFace::onCommitAlpha(const LLSD& data)
 {
 	sendAlpha();
@@ -993,11 +1469,122 @@ void LLPanelFace::onSelectColor(const LLSD& data)
 	sendColor();
 }
 
+// static
+void LLPanelFace::onCommitMaterialsMedia(LLUICtrl* ctrl, void* userdata)
+{
+	LLPanelFace* self = (LLPanelFace*) userdata;
+	// Force to default states to side-step problems with menu contents
+	// and generally reflecting old state when switching tabs or objects
+	//
+	self->updateShinyControls(false,true);
+	self->updateBumpyControls(false,true);
+	self->updateUI();
+}
+
+// static
+void LLPanelFace::updateVisibility()
+{	
+	LLComboBox* combo_matmedia = getChild<LLComboBox>("combobox matmedia");
+	LLComboBox* combo_mattype = getChild<LLComboBox>("combobox mattype");
+	LLComboBox* combo_shininess = getChild<LLComboBox>("combobox shininess");
+	LLComboBox* combo_bumpiness = getChild<LLComboBox>("combobox bumpiness");
+	if (!combo_mattype || !combo_matmedia || !combo_shininess || !combo_bumpiness)
+	{
+		LL_WARNS("Materials") << "Combo box not found...exiting." << LL_ENDL;
+		return;
+	}
+	U32 materials_media = combo_matmedia->getCurrentIndex();
+	U32 material_type = combo_mattype->getCurrentIndex();
+	bool show_media = (materials_media == MATMEDIA_MEDIA) && combo_matmedia->getEnabled();
+	bool show_texture = (show_media || ((material_type == MATTYPE_DIFFUSE) && combo_matmedia->getEnabled()));
+	bool show_bumpiness = (!show_media) && (material_type == MATTYPE_NORMAL) && combo_matmedia->getEnabled();
+	bool show_shininess = (!show_media) && (material_type == MATTYPE_SPECULAR) && combo_matmedia->getEnabled();
+	getChildView("combobox mattype")->setVisible(!show_media);
+	getChildView("rptctrl")->setVisible(true);
+
+	// Media controls
+	getChildView("media_info")->setVisible(show_media);
+	getChildView("add_media")->setVisible(show_media);
+	getChildView("delete_media")->setVisible(show_media);
+	getChildView("button align")->setVisible(show_media);
+
+	// Diffuse texture controls
+	getChildView("texture control")->setVisible(show_texture && !show_media);
+	getChildView("label alphamode")->setVisible(show_texture && !show_media);
+	getChildView("combobox alphamode")->setVisible(show_texture && !show_media);
+	getChildView("label maskcutoff")->setVisible(false);
+	getChildView("maskcutoff")->setVisible(false);
+	if (show_texture && !show_media)
+	{
+		updateAlphaControls();
+	}
+	getChildView("TexScaleU")->setVisible(show_texture);
+	getChildView("TexScaleV")->setVisible(show_texture);
+	getChildView("TexRot")->setVisible(show_texture);
+	getChildView("TexOffsetU")->setVisible(show_texture);
+	getChildView("TexOffsetV")->setVisible(show_texture);
+
+	// Specular map controls
+	getChildView("shinytexture control")->setVisible(show_shininess);
+	getChildView("combobox shininess")->setVisible(show_shininess);
+	getChildView("label shininess")->setVisible(show_shininess);
+	getChildView("label glossiness")->setVisible(false);
+	getChildView("glossiness")->setVisible(false);
+	getChildView("label environment")->setVisible(false);
+	getChildView("environment")->setVisible(false);
+	getChildView("label shinycolor")->setVisible(false);
+	getChildView("shinycolorswatch")->setVisible(false);
+	if (show_shininess)
+	{
+		updateShinyControls();
+	}
+	getChildView("shinyScaleU")->setVisible(show_shininess);
+	getChildView("shinyScaleV")->setVisible(show_shininess);
+	getChildView("shinyRot")->setVisible(show_shininess);
+	getChildView("shinyOffsetU")->setVisible(show_shininess);
+	getChildView("shinyOffsetV")->setVisible(show_shininess);
+
+	// Normal map controls
+	if (show_bumpiness)
+	{
+		updateBumpyControls();
+	}
+	getChildView("bumpytexture control")->setVisible(show_bumpiness);
+	getChildView("combobox bumpiness")->setVisible(show_bumpiness);
+	getChildView("label bumpiness")->setVisible(show_bumpiness);
+	getChildView("bumpyScaleU")->setVisible(show_bumpiness);
+	getChildView("bumpyScaleV")->setVisible(show_bumpiness);
+	getChildView("bumpyRot")->setVisible(show_bumpiness);
+	getChildView("bumpyOffsetU")->setVisible(show_bumpiness);
+	getChildView("bumpyOffsetV")->setVisible(show_bumpiness);
+
+
+}
+
+// static
+void LLPanelFace::onCommitMaterialType(LLUICtrl* ctrl, void* userdata)
+{
+    LLPanelFace* self = (LLPanelFace*) userdata;
+	 // Force to default states to side-step problems with menu contents
+	 // and generally reflecting old state when switching tabs or objects
+	 //
+	 self->updateShinyControls(false,true);
+	 self->updateBumpyControls(false,true);
+    self->updateUI();
+}
+
 // static
 void LLPanelFace::onCommitBump(LLUICtrl* ctrl, void* userdata)
 {
 	LLPanelFace* self = (LLPanelFace*) userdata;
-	self->sendBump();
+
+	LLComboBox*	mComboBumpiness = self->getChild<LLComboBox>("combobox bumpiness");
+	if(!mComboBumpiness)
+		return;
+
+	U32 bumpiness = mComboBumpiness->getCurrentIndex();
+
+	self->sendBump(bumpiness);
 }
 
 // static
@@ -1007,11 +1594,144 @@ void LLPanelFace::onCommitTexGen(LLUICtrl* ctrl, void* userdata)
 	self->sendTexGen();
 }
 
+// static
+void LLPanelFace::updateShinyControls(bool is_setting_texture, bool mess_with_shiny_combobox)
+{
+	LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>("shinytexture control");
+	LLUUID shiny_texture_ID = texture_ctrl->getImageAssetID();
+	LL_DEBUGS("Materials") << "Shiny texture selected: " << shiny_texture_ID << LL_ENDL;
+	LLComboBox* comboShiny = getChild<LLComboBox>("combobox shininess");
+
+	if(mess_with_shiny_combobox)
+	{
+		if (!comboShiny)
+		{
+			return;
+		}
+		if (!shiny_texture_ID.isNull() && is_setting_texture)
+		{
+			if (!comboShiny->itemExists(USE_TEXTURE))
+			{
+				comboShiny->add(USE_TEXTURE);
+			}
+			comboShiny->setSimple(USE_TEXTURE);
+		}
+		else
+		{
+			if (comboShiny->itemExists(USE_TEXTURE))
+			{
+				comboShiny->remove(SHINY_TEXTURE);
+				comboShiny->selectFirstItem();
+			}
+		}
+	}
+
+	LLComboBox* combo_matmedia = getChild<LLComboBox>("combobox matmedia");
+	LLComboBox* combo_mattype = getChild<LLComboBox>("combobox mattype");
+	U32 materials_media = combo_matmedia->getCurrentIndex();
+	U32 material_type = combo_mattype->getCurrentIndex();
+	bool show_media = (materials_media == MATMEDIA_MEDIA) && combo_matmedia->getEnabled();
+	bool show_shininess = (!show_media) && (material_type == MATTYPE_SPECULAR) && combo_matmedia->getEnabled();
+	U32 shiny_value = comboShiny->getCurrentIndex();
+	bool show_shinyctrls = (shiny_value == SHINY_TEXTURE) && show_shininess; // Use texture
+	getChildView("label glossiness")->setVisible(show_shinyctrls);
+	getChildView("glossiness")->setVisible(show_shinyctrls);
+	getChildView("label environment")->setVisible(show_shinyctrls);
+	getChildView("environment")->setVisible(show_shinyctrls);
+	getChildView("label shinycolor")->setVisible(show_shinyctrls);
+	getChildView("shinycolorswatch")->setVisible(show_shinyctrls);
+}
+
+// static
+void LLPanelFace::updateBumpyControls(bool is_setting_texture, bool mess_with_combobox)
+{
+	LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>("bumpytexture control");
+	LLUUID bumpy_texture_ID = texture_ctrl->getImageAssetID();
+	LL_DEBUGS("Materials") << "texture: " << bumpy_texture_ID << (mess_with_combobox ? "" : " do not") << " update combobox" << LL_ENDL;
+	LLComboBox* comboBumpy = getChild<LLComboBox>("combobox bumpiness");
+	if (!comboBumpy)
+	{
+		return;
+	}
+
+	if (mess_with_combobox)
+	{
+		LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>("bumpytexture control");
+		LLUUID bumpy_texture_ID = texture_ctrl->getImageAssetID();
+		LL_DEBUGS("Materials") << "texture: " << bumpy_texture_ID << (mess_with_combobox ? "" : " do not") << " update combobox" << LL_ENDL;
+
+		if (!bumpy_texture_ID.isNull() && is_setting_texture)
+		{
+			if (!comboBumpy->itemExists(USE_TEXTURE))
+			{
+				comboBumpy->add(USE_TEXTURE);
+			}
+			comboBumpy->setSimple(USE_TEXTURE);
+		}
+		else
+		{
+			if (comboBumpy->itemExists(USE_TEXTURE))
+			{
+				comboBumpy->remove(BUMPY_TEXTURE);
+				comboBumpy->selectFirstItem();
+			}
+		}
+	}
+}
+
 // static
 void LLPanelFace::onCommitShiny(LLUICtrl* ctrl, void* userdata)
 {
 	LLPanelFace* self = (LLPanelFace*) userdata;
-	self->sendShiny();
+
+
+	LLComboBox*	mComboShininess = self->getChild<LLComboBox>("combobox shininess");
+	if(!mComboShininess)
+		return;
+	
+	U32 shininess = mComboShininess->getCurrentIndex();
+
+	self->sendShiny(shininess);
+}
+
+// static
+void LLPanelFace::updateAlphaControls()
+{
+	LLComboBox* comboAlphaMode = getChild<LLComboBox>("combobox alphamode");
+	if (!comboAlphaMode)
+	{
+		return;
+	}
+	U32 alpha_value = comboAlphaMode->getCurrentIndex();
+	bool show_alphactrls = (alpha_value == ALPHAMODE_MASK); // Alpha masking
+    
+    LLComboBox* combobox_matmedia = getChild<LLComboBox>("combobox matmedia");
+    U32 mat_media = MATMEDIA_MATERIAL;
+    if (combobox_matmedia)
+    {
+        mat_media = combobox_matmedia->getCurrentIndex();
+    }
+    
+    LLComboBox* combobox_mattype = getChild<LLComboBox>("combobox mattype");
+    U32 mat_type = MATTYPE_DIFFUSE;
+    if (combobox_mattype)
+    {
+        mat_type = combobox_mattype->getCurrentIndex();
+    }
+
+    show_alphactrls = show_alphactrls && (mat_media == MATMEDIA_MATERIAL);
+    show_alphactrls = show_alphactrls && (mat_type == MATTYPE_DIFFUSE);
+    
+	getChildView("label maskcutoff")->setVisible(show_alphactrls);
+	getChildView("maskcutoff")->setVisible(show_alphactrls);
+}
+
+// static
+void LLPanelFace::onCommitAlphaMode(LLUICtrl* ctrl, void* userdata)
+{
+	LLPanelFace* self = (LLPanelFace*) userdata;
+	self->updateAlphaControls();
+	LLSelectedTEMaterial::setDiffuseAlphaMode(self,self->getCurrentDiffuseAlphaMode());
 }
 
 // static
@@ -1061,8 +1781,211 @@ void LLPanelFace::onSelectTexture(const LLSD& data)
 {
 	LLSelectMgr::getInstance()->saveSelectedObjectTextures();
 	sendTexture();
+
+	LLGLenum image_format;
+	bool identical_image_format = false;
+	LLSelectedTE::getImageFormat(image_format, identical_image_format);
+    
+	LLCtrlSelectionInterface* combobox_alphamode =
+		childGetSelectionInterface("combobox alphamode");
+
+	U32 alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
+	if (combobox_alphamode)
+	{
+		switch (image_format)
+		{
+		case GL_RGBA:
+		case GL_ALPHA:
+			{
+				alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND;
+			}
+			break;
+
+		case GL_RGB: break;
+		default:
+			{
+				llwarns << "Unexpected tex format in LLPanelFace...resorting to no alpha" << llendl;
+			}
+			break;
+		}
+
+		combobox_alphamode->selectNthItem(alpha_mode);
+	}
+	LLSelectedTEMaterial::setDiffuseAlphaMode(this, getCurrentDiffuseAlphaMode());
 }
 
+void LLPanelFace::onCloseTexturePicker(const LLSD& data)
+{
+	LL_DEBUGS("Materials") << data << LL_ENDL;
+	updateUI();
+}
+
+void LLPanelFace::onCommitSpecularTexture( const LLSD& data )
+{
+	LL_DEBUGS("Materials") << data << LL_ENDL;
+	sendShiny(SHINY_TEXTURE);
+}
+
+void LLPanelFace::onCommitNormalTexture( const LLSD& data )
+{
+	LL_DEBUGS("Materials") << data << LL_ENDL;
+	LLUUID nmap_id = getCurrentNormalMap();
+	sendBump(nmap_id.isNull() ? 0 : BUMPY_TEXTURE);
+}
+
+void LLPanelFace::onCancelSpecularTexture(const LLSD& data)
+{
+	U8 shiny = 0;
+	bool identical_shiny = false;
+	LLSelectedTE::getShiny(shiny, identical_shiny);
+	LLUUID spec_map_id = getChild<LLTextureCtrl>("shinytexture control")->getImageAssetID();
+	shiny = spec_map_id.isNull() ? shiny : SHINY_TEXTURE;
+	sendShiny(shiny);
+}
+
+void LLPanelFace::onCancelNormalTexture(const LLSD& data)
+{
+	U8 bumpy = 0;
+	bool identical_bumpy = false;
+	LLSelectedTE::getBumpmap(bumpy, identical_bumpy);
+	sendBump(bumpy);
+}
+
+void LLPanelFace::onSelectSpecularTexture(const LLSD& data)
+{
+	LL_DEBUGS("Materials") << data << LL_ENDL;
+	sendShiny(SHINY_TEXTURE);
+}
+
+void LLPanelFace::onSelectNormalTexture(const LLSD& data)
+{
+	LL_DEBUGS("Materials") << data << LL_ENDL;
+	LLUUID nmap_id = getCurrentNormalMap();
+	sendBump(nmap_id.isNull() ? 0 : BUMPY_TEXTURE);
+}
+
+//static
+void LLPanelFace::onCommitMaterialBumpyOffsetX(LLUICtrl* ctrl, void* userdata)
+{
+	LLPanelFace* self = (LLPanelFace*) userdata;
+	llassert_always(self);
+	LLSelectedTEMaterial::setNormalOffsetX(self,self->getCurrentBumpyOffsetU());
+}
+
+//static
+void LLPanelFace::onCommitMaterialBumpyOffsetY(LLUICtrl* ctrl, void* userdata)
+{
+	LLPanelFace* self = (LLPanelFace*) userdata;
+	llassert_always(self);
+	LLSelectedTEMaterial::setNormalOffsetY(self,self->getCurrentBumpyOffsetV());
+}
+
+//static
+void LLPanelFace::onCommitMaterialShinyOffsetX(LLUICtrl* ctrl, void* userdata)
+{
+	LLPanelFace* self = (LLPanelFace*) userdata;
+	llassert_always(self);
+	LLSelectedTEMaterial::setSpecularOffsetX(self,self->getCurrentShinyOffsetU());
+}
+
+//static
+void LLPanelFace::onCommitMaterialShinyOffsetY(LLUICtrl* ctrl, void* userdata)
+{
+	LLPanelFace* self = (LLPanelFace*) userdata;
+	llassert_always(self);
+	LLSelectedTEMaterial::setSpecularOffsetY(self,self->getCurrentShinyOffsetV());
+}
+
+//static
+void LLPanelFace::onCommitMaterialBumpyScaleX(LLUICtrl* ctrl, void* userdata)
+{
+	LLPanelFace* self = (LLPanelFace*) userdata;
+	llassert_always(self);
+	F32 bumpy_scale_u = self->getCurrentBumpyScaleU();
+	if (self->isIdenticalPlanarTexgen())
+	{
+		bumpy_scale_u *= 0.5f;
+	}
+	LLSelectedTEMaterial::setNormalRepeatX(self,bumpy_scale_u);
+}
+
+//static
+void LLPanelFace::onCommitMaterialBumpyScaleY(LLUICtrl* ctrl, void* userdata)
+{
+	LLPanelFace* self = (LLPanelFace*) userdata;
+	llassert_always(self);
+	F32 bumpy_scale_v = self->getCurrentBumpyScaleV();
+	if (self->isIdenticalPlanarTexgen())
+	{
+		bumpy_scale_v *= 0.5f;
+	}
+	LLSelectedTEMaterial::setNormalRepeatY(self,bumpy_scale_v);
+}
+
+//static
+void LLPanelFace::onCommitMaterialShinyScaleX(LLUICtrl* ctrl, void* userdata)
+{
+	LLPanelFace* self = (LLPanelFace*) userdata;
+	llassert_always(self);
+	F32 shiny_scale_u = self->getCurrentShinyScaleU();
+	if (self->isIdenticalPlanarTexgen())
+	{
+		shiny_scale_u *= 0.5f;
+	}
+	LLSelectedTEMaterial::setSpecularRepeatX(self,shiny_scale_u);
+}
+
+//static
+void LLPanelFace::onCommitMaterialShinyScaleY(LLUICtrl* ctrl, void* userdata)
+{
+	LLPanelFace* self = (LLPanelFace*) userdata;
+	llassert_always(self);
+	F32 shiny_scale_v = self->getCurrentShinyScaleV();
+	if (self->isIdenticalPlanarTexgen())
+	{
+		shiny_scale_v *= 0.5f;
+	}
+	LLSelectedTEMaterial::setSpecularRepeatY(self,shiny_scale_v);
+}
+
+//static
+void LLPanelFace::onCommitMaterialBumpyRot(LLUICtrl* ctrl, void* userdata)
+{
+	LLPanelFace* self = (LLPanelFace*) userdata;
+	llassert_always(self);
+	LLSelectedTEMaterial::setNormalRotation(self,self->getCurrentBumpyRot() * DEG_TO_RAD);
+}
+
+//static
+void LLPanelFace::onCommitMaterialShinyRot(LLUICtrl* ctrl, void* userdata)
+{
+	LLPanelFace* self = (LLPanelFace*) userdata;
+	llassert_always(self);
+	LLSelectedTEMaterial::setSpecularRotation(self,self->getCurrentShinyRot() * DEG_TO_RAD);
+}
+
+//static
+void LLPanelFace::onCommitMaterialGloss(LLUICtrl* ctrl, void* userdata)
+{
+	LLPanelFace* self = (LLPanelFace*) userdata;
+	llassert_always(self);
+	LLSelectedTEMaterial::setSpecularLightExponent(self,self->getCurrentGlossiness());
+}
+
+//static
+void LLPanelFace::onCommitMaterialEnv(LLUICtrl* ctrl, void* userdata)
+{
+	LLPanelFace* self = (LLPanelFace*) userdata;
+	llassert_always(self);
+	LLSelectedTEMaterial::setEnvironmentIntensity(self,self->getCurrentEnvIntensity());
+}
+
+//static
+void LLPanelFace::onCommitMaterialMaskCutoff(LLUICtrl* ctrl, void* userdata)
+{
+	LLPanelFace* self = (LLPanelFace*) userdata;
+	LLSelectedTEMaterial::setAlphaMaskCutoff(self,self->getCurrentAlphaMaskCutoff());
+}
 
 // static
 void LLPanelFace::onCommitTextureInfo( LLUICtrl* ctrl, void* userdata )
@@ -1073,15 +1996,67 @@ void LLPanelFace::onCommitTextureInfo( LLUICtrl* ctrl, void* userdata )
 
 // Commit the number of repeats per meter
 // static
-void LLPanelFace::onClickApply(void* userdata)
+void LLPanelFace::onCommitRepeatsPerMeter(LLUICtrl* ctrl, void* userdata)
 {
 	LLPanelFace* self = (LLPanelFace*) userdata;
 	
-	gFocusMgr.setKeyboardFocus( NULL );
+	LLUICtrl*	repeats_ctrl	= self->getChild<LLUICtrl>("rptctrl");
+	LLComboBox* combo_matmedia = self->getChild<LLComboBox>("combobox matmedia");
+	LLComboBox* combo_mattype	= self->getChild<LLComboBox>("combobox mattype");
+	
+	U32 materials_media = combo_matmedia->getCurrentIndex();
+	
+
+	U32 material_type			= (materials_media == MATMEDIA_MATERIAL) ? combo_mattype->getCurrentIndex() : 0;
+	F32 repeats_per_meter	= repeats_ctrl->getValue().asReal();
+	
+   F32 obj_scale_s = 1.0f;
+   F32 obj_scale_t = 1.0f;
+
+	bool identical_scale_s = false;
+	bool identical_scale_t = false;
+
+	LLSelectedTE::getObjectScaleS(obj_scale_s, identical_scale_s);
+	LLSelectedTE::getObjectScaleS(obj_scale_t, identical_scale_t);
+ 
+	switch (material_type)
+	{
+		case MATTYPE_DIFFUSE:
+		{
+			LLSelectMgr::getInstance()->selectionTexScaleAutofit( repeats_per_meter );
+		}
+		break;
+
+		case MATTYPE_NORMAL:
+		{
+			LLUICtrl* bumpy_scale_u = self->getChild<LLUICtrl>("bumpyScaleU");
+			LLUICtrl* bumpy_scale_v = self->getChild<LLUICtrl>("bumpyScaleV");
+			
+			bumpy_scale_u->setValue(obj_scale_s * repeats_per_meter);
+			bumpy_scale_v->setValue(obj_scale_t * repeats_per_meter);
+
+			LLSelectedTEMaterial::setNormalRepeatX(self,obj_scale_s * repeats_per_meter);
+			LLSelectedTEMaterial::setNormalRepeatY(self,obj_scale_t * repeats_per_meter);
+		}
+		break;
+
+		case MATTYPE_SPECULAR:
+		{
+			LLUICtrl* shiny_scale_u = self->getChild<LLUICtrl>("shinyScaleU");
+			LLUICtrl* shiny_scale_v = self->getChild<LLUICtrl>("shinyScaleV");
+			
+			shiny_scale_u->setValue(obj_scale_s * repeats_per_meter);
+			shiny_scale_v->setValue(obj_scale_t * repeats_per_meter);
 
-	//F32 repeats_per_meter = self->mCtrlRepeatsPerMeter->get();
-	F32 repeats_per_meter = (F32)self->getChild<LLUICtrl>("rptctrl")->getValue().asReal();//self->mCtrlRepeatsPerMeter->get();
-	LLSelectMgr::getInstance()->selectionTexScaleAutofit( repeats_per_meter );
+			LLSelectedTEMaterial::setSpecularRepeatX(self,obj_scale_s * repeats_per_meter);
+			LLSelectedTEMaterial::setSpecularRepeatY(self,obj_scale_t * repeats_per_meter);
+		}
+		break;
+
+		default:
+			llassert(false);
+		break;
+	}
 }
 
 struct LLPanelFaceSetMediaFunctor : public LLSelectedTEFunctor
@@ -1155,7 +2130,26 @@ void LLPanelFace::onCommitPlanarAlign(LLUICtrl* ctrl, void* userdata)
 
 void LLPanelFace::onTextureSelectionChanged(LLInventoryItem* itemp)
 {
-	LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>("texture control");
+	LL_DEBUGS("Materials") << "item asset " << itemp->getAssetUUID() << LL_ENDL;
+	LLComboBox* combo_mattype = getChild<LLComboBox>("combobox mattype");
+	if (!combo_mattype)
+	{
+		return;
+	}
+	U32 mattype = combo_mattype->getCurrentIndex();
+	std::string which_control="texture control";
+	switch (mattype)
+	{
+		case MATTYPE_SPECULAR:
+			which_control = "shinytexture control";
+			break;
+		case MATTYPE_NORMAL:
+			which_control = "bumpytexture control";
+			break;
+		// no default needed
+	}
+	LL_DEBUGS("Materials") << "control " << which_control << LL_ENDL;
+	LLTextureCtrl* texture_ctrl = getChild<LLTextureCtrl>(which_control);
 	if (texture_ctrl)
 	{
 		LLUUID obj_owner_id;
@@ -1185,3 +2179,212 @@ void LLPanelFace::onTextureSelectionChanged(LLInventoryItem* itemp)
 		}
 	}
 }
+
+bool LLPanelFace::isIdenticalPlanarTexgen()
+{
+	LLTextureEntry::e_texgen selected_texgen = LLTextureEntry::TEX_GEN_DEFAULT;
+	bool identical_texgen = false;
+	LLSelectedTE::getTexGen(selected_texgen, identical_texgen);
+	return (identical_texgen && (selected_texgen == LLTextureEntry::TEX_GEN_PLANAR));
+}
+
+void LLPanelFace::LLSelectedTE::getFace(LLFace*& face_to_return, bool& identical_face)
+{		
+	struct LLSelectedTEGetFace : public LLSelectedTEGetFunctor<LLFace *>
+	{
+		LLFace* get(LLViewerObject* object, S32 te)
+		{
+			return (object->mDrawable) ? object->mDrawable->getFace(te): NULL;
+		}
+	} get_te_face_func;
+	identical_face = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_te_face_func, face_to_return);
+}
+
+void LLPanelFace::LLSelectedTE::getImageFormat(LLGLenum& image_format_to_return, bool& identical_face)
+{
+	LLGLenum image_format;
+	struct LLSelectedTEGetImageFormat : public LLSelectedTEGetFunctor<LLGLenum>
+	{
+		LLGLenum get(LLViewerObject* object, S32 te_index)
+		{
+			LLViewerTexture* image = object->getTEImage(te_index);
+			return image ? image->getPrimaryFormat() : GL_RGB;
+		}
+	} get_glenum;
+	identical_face = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue(&get_glenum, image_format);
+	image_format_to_return = image_format;
+}
+
+void LLPanelFace::LLSelectedTE::getTexId(LLUUID& id, bool& identical)
+{		
+	struct LLSelectedTEGetTexId : public LLSelectedTEGetFunctor<LLUUID>
+	{
+		LLUUID get(LLViewerObject* object, S32 te_index)
+		{
+			LLUUID id;
+			LLViewerTexture* image = object->getTEImage(te_index);
+			if (image)
+			{
+				id = image->getID();
+			}
+
+			if (!id.isNull() && LLViewerMedia::textureHasMedia(id))
+			{
+				LLTextureEntry *te = object->getTE(te_index);
+				if (te)
+				{
+					LLViewerTexture* tex = te->getID().notNull() ? gTextureList.findImage(te->getID()) : NULL;
+					if(!tex)
+					{
+						tex = LLViewerFetchedTexture::sDefaultImagep;
+					}
+					if (tex)
+					{
+						id = tex->getID();
+					}
+				}
+			}
+			return id;
+		}
+	} func;
+	identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, id );
+}
+
+void LLPanelFace::LLSelectedTEMaterial::getCurrent(LLMaterialPtr& material_ptr, bool& identical_material)
+{
+	struct MaterialFunctor : public LLSelectedTEGetFunctor<LLMaterialPtr>
+	{
+		LLMaterialPtr get(LLViewerObject* object, S32 te_index)
+		{
+			return object->getTE(te_index)->getMaterialParams();
+		}
+	} func;
+	identical_material = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, material_ptr);
+}
+
+void LLPanelFace::LLSelectedTEMaterial::getMaxSpecularRepeats(F32& repeats, bool& identical)
+{
+	struct LLSelectedTEGetMaxSpecRepeats : public LLSelectedTEGetFunctor<F32>
+	{
+		F32 get(LLViewerObject* object, S32 face)
+		{
+			LLMaterial* mat = object->getTE(face)->getMaterialParams().get();
+			U32 s_axis = VX;
+			U32 t_axis = VY;
+			F32 repeats_s = 1.0f;
+			F32 repeats_t = 1.0f;
+			if (mat)
+			{
+				mat->getSpecularRepeat(repeats_s, repeats_t);
+				repeats_s /= object->getScale().mV[s_axis];
+				repeats_t /= object->getScale().mV[t_axis];
+			}					
+			return llmax(repeats_s, repeats_t);
+		}
+
+	} max_spec_repeats_func;
+	identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &max_spec_repeats_func, repeats);
+}
+
+void LLPanelFace::LLSelectedTEMaterial::getMaxNormalRepeats(F32& repeats, bool& identical)
+{
+	struct LLSelectedTEGetMaxNormRepeats : public LLSelectedTEGetFunctor<F32>
+	{
+		F32 get(LLViewerObject* object, S32 face)
+		{
+			LLMaterial* mat = object->getTE(face)->getMaterialParams().get();
+			U32 s_axis = VX;
+			U32 t_axis = VY;
+			F32 repeats_s = 1.0f;
+			F32 repeats_t = 1.0f;
+			if (mat)
+			{
+				mat->getNormalRepeat(repeats_s, repeats_t);
+				repeats_s /= object->getScale().mV[s_axis];
+				repeats_t /= object->getScale().mV[t_axis];
+			}					
+			return llmax(repeats_s, repeats_t);
+		}
+
+	} max_norm_repeats_func;
+	identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &max_norm_repeats_func, repeats);
+}
+
+void LLPanelFace::LLSelectedTEMaterial::getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, bool diffuse_texture_has_alpha)
+{
+	struct LLSelectedTEGetDiffuseAlphaMode : public LLSelectedTEGetFunctor<U8>
+	{
+		LLSelectedTEGetDiffuseAlphaMode() : _isAlpha(false) {}
+		LLSelectedTEGetDiffuseAlphaMode(bool diffuse_texture_has_alpha) : _isAlpha(diffuse_texture_has_alpha) {}
+		virtual ~LLSelectedTEGetDiffuseAlphaMode() {}
+
+		U8 get(LLViewerObject* object, S32 face)
+		{
+			U8 diffuse_mode = _isAlpha ? LLMaterial::DIFFUSE_ALPHA_MODE_BLEND : LLMaterial::DIFFUSE_ALPHA_MODE_NONE;
+
+			LLTextureEntry* tep = object->getTE(face);
+			if (tep)
+			{
+				LLMaterial* mat = tep->getMaterialParams().get();
+				if (mat)
+				{
+					diffuse_mode = mat->getDiffuseAlphaMode();
+				}
+			}
+			
+			return diffuse_mode;
+		}
+		bool _isAlpha; // whether or not the diffuse texture selected contains alpha information
+	} get_diff_mode(diffuse_texture_has_alpha);
+	identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &get_diff_mode, diffuse_alpha_mode);
+}
+
+void LLPanelFace::LLSelectedTE::getObjectScaleS(F32& scale_s, bool& identical)
+{	
+	struct LLSelectedTEGetObjectScaleS : public LLSelectedTEGetFunctor<F32>
+	{
+		F32 get(LLViewerObject* object, S32 face)
+		{
+			U32 s_axis = VX;
+			U32 t_axis = VY;
+			LLPrimitive::getTESTAxes(face, &s_axis, &t_axis);
+			return object->getScale().mV[s_axis];
+		}
+
+	} scale_s_func;
+	identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &scale_s_func, scale_s );
+}
+
+void LLPanelFace::LLSelectedTE::getObjectScaleT(F32& scale_t, bool& identical)
+{	
+	struct LLSelectedTEGetObjectScaleS : public LLSelectedTEGetFunctor<F32>
+	{
+		F32 get(LLViewerObject* object, S32 face)
+		{
+			U32 s_axis = VX;
+			U32 t_axis = VY;
+			LLPrimitive::getTESTAxes(face, &s_axis, &t_axis);
+			return object->getScale().mV[t_axis];
+		}
+
+	} scale_t_func;
+	identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &scale_t_func, scale_t );
+}
+
+void LLPanelFace::LLSelectedTE::getMaxDiffuseRepeats(F32& repeats, bool& identical)
+{
+	struct LLSelectedTEGetMaxDiffuseRepeats : public LLSelectedTEGetFunctor<F32>
+	{
+		F32 get(LLViewerObject* object, S32 face)
+		{
+			U32 s_axis = VX;
+			U32 t_axis = VY;
+			LLPrimitive::getTESTAxes(face, &s_axis, &t_axis);
+			F32 repeats_s = object->getTE(face)->mScaleS / object->getScale().mV[s_axis];
+			F32 repeats_t = object->getTE(face)->mScaleT / object->getScale().mV[t_axis];
+			return llmax(repeats_s, repeats_t);
+		}
+
+	} max_diff_repeats_func;
+	identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &max_diff_repeats_func, repeats );
+}
diff --git a/indra/newview/llpanelface.h b/indra/newview/llpanelface.h
index 3b5a9b1398c8d0fb111abb67215f8664cf1735c8..42c1f6bd4820c086ec946426705ae3cb20bcc3dd 100755
--- a/indra/newview/llpanelface.h
+++ b/indra/newview/llpanelface.h
@@ -29,6 +29,10 @@
 
 #include "v4color.h"
 #include "llpanel.h"
+#include "llmaterial.h"
+#include "llmaterialmgr.h"
+#include "lltextureentry.h"
+#include "llselectmgr.h"
 
 class LLButton;
 class LLCheckBoxCtrl;
@@ -42,6 +46,48 @@ class LLTextureCtrl;
 class LLUICtrl;
 class LLViewerObject;
 class LLFloater;
+class LLMaterialID;
+
+// Represents an edit for use in replicating the op across one or more materials in the selection set.
+//
+// The apply function optionally performs the edit which it implements
+// as a functor taking Data that calls member func MaterialFunc taking SetValueType
+// on an instance of the LLMaterial class.
+//
+// boost who?
+//
+template<
+	typename DataType,
+	typename SetValueType,
+	void (LLMaterial::*MaterialEditFunc)(SetValueType data) >
+class LLMaterialEditFunctor
+{
+public:
+	LLMaterialEditFunctor(const DataType& data) : _data(data) {}
+	virtual ~LLMaterialEditFunctor() {}
+	virtual void apply(LLMaterialPtr& material) { (material->*(MaterialEditFunc))(_data); }
+	DataType _data;
+};
+
+template<
+	typename DataType,
+	DataType (LLMaterial::*MaterialGetFunc)() >
+class LLMaterialGetFunctor
+{
+public:
+	LLMaterialGetFunctor() {}
+	virtual DataType get(LLMaterialPtr& material) { return (material->*(MaterialGetFunc)); }
+};
+
+template<
+	typename DataType,
+	DataType (LLTextureEntry::*TEGetFunc)() >
+class LLTEGetFunctor
+{
+public:
+	LLTEGetFunctor() {}
+	virtual DataType get(LLTextureEntry* entry) { return (entry*(TEGetFunc)); }
+};
 
 class LLPanelFace : public LLPanel
 {
@@ -61,11 +107,11 @@ class LLPanelFace : public LLPanel
 	void			sendTextureInfo();		// applies and sends texture scale, offset, etc.
 	void			sendColor();			// applies and sends color
 	void			sendAlpha();			// applies and sends transparency
-	void			sendBump();				// applies and sends bump map
+	void			sendBump(U32 bumpiness);				// applies and sends bump map
 	void			sendTexGen();				// applies and sends bump map
-	void			sendShiny();			// applies and sends shininess
+	void			sendShiny(U32 shininess);			// applies and sends shininess
 	void			sendFullbright();		// applies and sends full bright
-	void            sendGlow();
+	void        sendGlow();
 	void			sendMedia();
 
 	// this function is to return TRUE if the drag should succeed.
@@ -74,25 +120,228 @@ class LLPanelFace : public LLPanel
 	void 	onCommitTexture(const LLSD& data);
 	void 	onCancelTexture(const LLSD& data);
 	void 	onSelectTexture(const LLSD& data);
+	void 	onCommitSpecularTexture(const LLSD& data);
+	void 	onCancelSpecularTexture(const LLSD& data);
+	void 	onSelectSpecularTexture(const LLSD& data);
+	void 	onCommitNormalTexture(const LLSD& data);
+	void 	onCancelNormalTexture(const LLSD& data);
+	void 	onSelectNormalTexture(const LLSD& data);
 	void 	onCommitColor(const LLSD& data);
+	void 	onCommitShinyColor(const LLSD& data);
 	void 	onCommitAlpha(const LLSD& data);
 	void 	onCancelColor(const LLSD& data);
 	void 	onSelectColor(const LLSD& data);
-	
-	static 	void onCommitTextureInfo( 		LLUICtrl* ctrl, void* userdata);
-	static void		onCommitBump(			LLUICtrl* ctrl, void* userdata);
+
+	void 	onCloseTexturePicker(const LLSD& data);
+
+	// Make UI reflect state of currently selected material (refresh)
+	// and UI mode (e.g. editing normal map v diffuse map)
+	//
+	void updateUI();
+
+	// Convenience func to determine if all faces in selection have
+	// identical planar texgen settings during edits
+	// 
+	bool isIdenticalPlanarTexgen();
+
+	// Callback funcs for individual controls
+	//
+	static void		onCommitTextureInfo( 	LLUICtrl* ctrl, void* userdata);
+
+	static void		onCommitMaterialBumpyScaleX(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialBumpyScaleY(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialBumpyRot(		LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialBumpyOffsetX(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialBumpyOffsetY(	LLUICtrl* ctrl, void* userdata);
+
+	static void		onCommitMaterialShinyScaleX(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialShinyScaleY(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialShinyRot(		LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialShinyOffsetX(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialShinyOffsetY(	LLUICtrl* ctrl, void* userdata);
+
+	static void		onCommitMaterialGloss(			LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialEnv(				LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialMaskCutoff(	LLUICtrl* ctrl, void* userdata);
+
+	static void		onCommitMaterialsMedia(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitMaterialType(	LLUICtrl* ctrl, void* userdata);
+	static void		onCommitBump(				LLUICtrl* ctrl, void* userdata);
 	static void		onCommitTexGen(			LLUICtrl* ctrl, void* userdata);
-	static void		onCommitShiny(			LLUICtrl* ctrl, void* userdata);
+	static void		onCommitShiny(				LLUICtrl* ctrl, void* userdata);
+	static void		onCommitAlphaMode(		LLUICtrl* ctrl, void* userdata);
 	static void		onCommitFullbright(		LLUICtrl* ctrl, void* userdata);
-	static void     onCommitGlow(           LLUICtrl* ctrl, void *userdata);
-	static void		onCommitPlanarAlign(	LLUICtrl* ctrl, void* userdata);
-	
-	static void		onClickApply(void*);
+	static void    onCommitGlow(				LLUICtrl* ctrl, void *userdata);
+	static void		onCommitPlanarAlign(		LLUICtrl* ctrl, void* userdata);
+	static void		onCommitRepeatsPerMeter(	LLUICtrl* ctrl, void* userinfo);
 	static void		onClickAutoFix(void*);
-	static F32      valueGlow(LLViewerObject* object, S32 face);
+
+	static F32     valueGlow(LLViewerObject* object, S32 face);
 
 private:
 
+	bool		isAlpha() { return mIsAlpha; }
+
+	// Convenience funcs to keep the visual flack to a minimum
+	//
+	LLUUID	getCurrentNormalMap();
+	LLUUID	getCurrentSpecularMap();
+	U32		getCurrentShininess();
+	U32		getCurrentBumpiness();
+	U8			getCurrentDiffuseAlphaMode();
+	U8			getCurrentAlphaMaskCutoff();
+	U8			getCurrentEnvIntensity();
+	U8			getCurrentGlossiness();
+	F32		getCurrentBumpyRot();
+	F32		getCurrentBumpyScaleU();
+	F32		getCurrentBumpyScaleV();
+	F32		getCurrentBumpyOffsetU();
+	F32		getCurrentBumpyOffsetV();
+	F32		getCurrentShinyRot();
+	F32		getCurrentShinyScaleU();
+	F32		getCurrentShinyScaleV();
+	F32		getCurrentShinyOffsetU();
+	F32		getCurrentShinyOffsetV();
+
+	// Update visibility of controls to match current UI mode
+	// (e.g. materials vs media editing)
+	//
+	// Do NOT call updateUI from within this function.
+	//
+	void updateVisibility();
+
+	// Make material(s) reflect current state of UI (apply edit)
+	//
+	void updateMaterial();
+
+	// Hey look everyone, a type-safe alternative to copy and paste! :)
+	//
+
+	// Update material parameters by applying 'edit_func' to selected TEs
+	//
+	template<
+		typename DataType,
+		typename SetValueType,
+		void (LLMaterial::*MaterialEditFunc)(SetValueType data) >
+	static void edit(LLPanelFace* p, DataType data)
+	{
+		LLMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc > edit(data);
+		struct LLSelectedTEEditMaterial : public LLSelectedTEMaterialFunctor
+		{
+			LLSelectedTEEditMaterial(LLPanelFace* panel, LLMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc >* editp) : _panel(panel), _edit(editp) {}
+			virtual ~LLSelectedTEEditMaterial() {};
+			virtual LLMaterialPtr apply(LLViewerObject* object, S32 face, LLTextureEntry* tep, LLMaterialPtr& current_material)
+			{
+				if (_edit)
+				{
+					LLMaterialPtr new_material(!current_material.isNull() ? new LLMaterial(current_material->asLLSD()) : new LLMaterial());
+					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);
+
+					// Default to matching expected state of UI
+					//
+					new_material->setDiffuseAlphaMode(current_material.isNull() ? default_alpha_mode : current_material->getDiffuseAlphaMode());
+
+					// Do "It"!
+					//
+					_edit->apply(new_material);
+
+					U32		new_alpha_mode			= new_material->getDiffuseAlphaMode();
+					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);
+					bool is_need_material			= !is_default_blend_mode || !new_normal_map_id.isNull() || !new_spec_map_id.isNull();
+
+					if (!is_need_material)
+					{
+						LL_DEBUGS("Materials") << "Removing material from object " << object->getID() << " face " << face << LL_ENDL;
+						LLMaterialMgr::getInstance()->remove(object->getID(),face);
+						new_material = NULL;
+					}
+					else
+					{
+						LL_DEBUGS("Materials") << "Putting material on object " << object->getID() << " face " << face << ", material: " << new_material->asLLSD() << LL_ENDL;
+						LLMaterialMgr::getInstance()->put(object->getID(),face,*new_material);
+					}
+
+					object->setTEMaterialParams(face, new_material);
+					return new_material;
+				}
+				return NULL;
+			}
+			LLMaterialEditFunctor< DataType, SetValueType, MaterialEditFunc >*	_edit;
+			LLPanelFace*																			_panel;
+		} editor(p, &edit);
+		LLSelectMgr::getInstance()->selectionSetMaterialParams(&editor);
+	}
+
+	template<
+		typename DataType,
+		typename ReturnType,
+		ReturnType (LLMaterial::* const MaterialGetFunc)() const  >
+	static void getTEMaterialValue(DataType& data_to_return, bool& identical,DataType default_value)
+	{
+		DataType data_value;
+		struct GetTEMaterialVal : public LLSelectedTEGetFunctor<DataType>
+		{
+			GetTEMaterialVal(DataType default_value) : _default(default_value) {}
+			virtual ~GetTEMaterialVal() {}
+
+			DataType get(LLViewerObject* object, S32 face)
+			{
+				DataType ret = _default;
+				LLMaterialPtr material_ptr;
+				LLTextureEntry* tep = object ? object->getTE(face) : NULL;
+				if (tep)
+				{
+					material_ptr = tep->getMaterialParams();
+					if (!material_ptr.isNull())
+					{
+						ret = (material_ptr->*(MaterialGetFunc))();
+					}
+				}
+				return ret;
+			}
+			DataType _default;
+		} GetFunc(default_value);
+		identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &GetFunc, data_value);
+		data_to_return = data_value;
+	}
+
+	template<
+		typename DataType,
+		typename ReturnType, // some kids just have to different...
+		ReturnType (LLTextureEntry::* const TEGetFunc)() const >
+	static void getTEValue(DataType& data_to_return, bool& identical, DataType default_value)
+	{
+		DataType data_value;
+		struct GetTEVal : public LLSelectedTEGetFunctor<DataType>
+		{
+			GetTEVal(DataType default_value) : _default(default_value) {}
+			virtual ~GetTEVal() {}
+
+			DataType get(LLViewerObject* object, S32 face) {
+				LLTextureEntry* tep = object ? object->getTE(face) : NULL;
+				return tep ? ((tep->*(TEGetFunc))()) : _default;
+			}
+			DataType _default;
+		} GetTEValFunc(default_value);
+		identical = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &GetTEValFunc, data_value );
+		data_to_return = data_value;
+	}
+
+	// Update vis and enabling of specific subsets of controls based on material params
+	// (e.g. hide the spec controls if no spec texture is applied)
+	//
+	void updateShinyControls(bool is_setting_texture = false, bool mess_with_combobox = false);
+	void updateBumpyControls(bool is_setting_texture = false, bool mess_with_combobox = false);
+	void updateAlphaControls();
+
 	/*
 	 * Checks whether the selected texture from the LLFloaterTexturePicker can be applied to the currently selected object.
 	 * If agent selects texture which is not allowed to be applied for the currently selected object,
@@ -100,6 +349,126 @@ class LLPanelFace : public LLPanel
 	 */
 	void onTextureSelectionChanged(LLInventoryItem* itemp);
 
+	bool mIsAlpha;
+	
+	/* These variables interlock processing of materials updates sent to
+	 * the sim.  mUpdateInFlight is set to flag that an update has been
+	 * sent to the sim and not acknowledged yet, and cleared when an
+	 * update is received from the sim.  mUpdatePending is set when
+	 * there's an update in flight and another UI change has been made
+	 * that needs to be sent as a materials update, and cleared when the
+	 * update is sent.  This prevents the sim from getting spammed with
+	 * update messages when, for example, the user holds down the
+	 * up-arrow on a spinner, and avoids running afoul of its throttle.
+	 */
+	bool mUpdateInFlight;
+	bool mUpdatePending;
+
+	#if defined(DEF_GET_MAT_STATE)
+		#undef DEF_GET_MAT_STATE
+	#endif
+
+	#if defined(DEF_GET_TE_STATE)
+		#undef DEF_GET_TE_STATE
+	#endif
+
+	#if defined(DEF_EDIT_MAT_STATE)
+		DEF_EDIT_MAT_STATE
+	#endif
+
+	// Accessors for selected TE material state
+	//
+	#define DEF_GET_MAT_STATE(DataType,ReturnType,MaterialMemberFunc,DefaultValue)												\
+		static void MaterialMemberFunc(DataType& data, bool& identical)																\
+		{																																					\
+			getTEMaterialValue< DataType, ReturnType, &LLMaterial::MaterialMemberFunc >(data, identical,DefaultValue);	\
+		}
+
+	// Mutators for selected TE material
+	//
+	#define DEF_EDIT_MAT_STATE(DataType,ReturnType,MaterialMemberFunc)																\
+		static void MaterialMemberFunc(LLPanelFace* p,DataType data)																	\
+		{																																					\
+			edit< DataType, ReturnType, &LLMaterial::MaterialMemberFunc >(p,data);													\
+		}
+
+	// Accessors for selected TE state proper (legacy settings etc)
+	//
+	#define DEF_GET_TE_STATE(DataType,ReturnType,TexEntryMemberFunc,DefaultValue)													\
+		static void TexEntryMemberFunc(DataType& data, bool& identical)																\
+		{																																					\
+			getTEValue< DataType, ReturnType, &LLTextureEntry::TexEntryMemberFunc >(data, identical,DefaultValue);		\
+		}
+
+	class LLSelectedTEMaterial
+	{
+	public:
+		static void getCurrent(LLMaterialPtr& material_ptr, bool& identical_material);
+		static void getMaxSpecularRepeats(F32& repeats, bool& identical);
+		static void getMaxNormalRepeats(F32& repeats, bool& identical);
+		static void getCurrentDiffuseAlphaMode(U8& diffuse_alpha_mode, bool& identical, bool diffuse_texture_has_alpha);
+
+		DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getNormalID,LLUUID::null)
+		DEF_GET_MAT_STATE(LLUUID,const LLUUID&,getSpecularID,LLUUID::null)
+		DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatX,1.0f)
+		DEF_GET_MAT_STATE(F32,F32,getSpecularRepeatY,1.0f)
+		DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetX,0.0f)
+		DEF_GET_MAT_STATE(F32,F32,getSpecularOffsetY,0.0f)
+		DEF_GET_MAT_STATE(F32,F32,getSpecularRotation,0.0f)
+
+		DEF_GET_MAT_STATE(F32,F32,getNormalRepeatX,1.0f)
+		DEF_GET_MAT_STATE(F32,F32,getNormalRepeatY,1.0f)
+		DEF_GET_MAT_STATE(F32,F32,getNormalOffsetX,0.0f)
+		DEF_GET_MAT_STATE(F32,F32,getNormalOffsetY,0.0f)
+		DEF_GET_MAT_STATE(F32,F32,getNormalRotation,0.0f)
+
+		DEF_EDIT_MAT_STATE(U8,U8,setDiffuseAlphaMode);
+		DEF_EDIT_MAT_STATE(U8,U8,setAlphaMaskCutoff);
+
+		DEF_EDIT_MAT_STATE(F32,F32,setNormalOffsetX);
+		DEF_EDIT_MAT_STATE(F32,F32,setNormalOffsetY);
+		DEF_EDIT_MAT_STATE(F32,F32,setNormalRepeatX);
+		DEF_EDIT_MAT_STATE(F32,F32,setNormalRepeatY);
+		DEF_EDIT_MAT_STATE(F32,F32,setNormalRotation);
+
+		DEF_EDIT_MAT_STATE(F32,F32,setSpecularOffsetX);
+		DEF_EDIT_MAT_STATE(F32,F32,setSpecularOffsetY);
+		DEF_EDIT_MAT_STATE(F32,F32,setSpecularRepeatX);
+		DEF_EDIT_MAT_STATE(F32,F32,setSpecularRepeatY);
+		DEF_EDIT_MAT_STATE(F32,F32,setSpecularRotation);
+
+		DEF_EDIT_MAT_STATE(U8,U8,setEnvironmentIntensity);
+		DEF_EDIT_MAT_STATE(U8,U8,setSpecularLightExponent);
+
+		DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setNormalID);
+		DEF_EDIT_MAT_STATE(LLUUID,const LLUUID&,setSpecularID);
+		DEF_EDIT_MAT_STATE(LLColor4U,	const LLColor4U&,setSpecularLightColor);
+	};
+
+	class LLSelectedTE
+	{
+	public:
+
+		static void getFace(LLFace*& face_to_return, bool& identical_face);
+		static void getImageFormat(LLGLenum& image_format_to_return, bool& identical_face);
+		static void getTexId(LLUUID& id, bool& identical);
+		static void getObjectScaleS(F32& scale_s, bool& identical);
+		static void getObjectScaleT(F32& scale_t, bool& identical);
+		static void getMaxDiffuseRepeats(F32& repeats, bool& identical);
+
+		DEF_GET_TE_STATE(U8,U8,getBumpmap,0)
+		DEF_GET_TE_STATE(U8,U8,getShiny,0)
+		DEF_GET_TE_STATE(U8,U8,getFullbright,0)
+		DEF_GET_TE_STATE(F32,F32,getRotation,0.0f)
+		DEF_GET_TE_STATE(F32,F32,getOffsetS,0.0f)
+		DEF_GET_TE_STATE(F32,F32,getOffsetT,0.0f)
+		DEF_GET_TE_STATE(F32,F32,getScaleS,1.0f)
+		DEF_GET_TE_STATE(F32,F32,getScaleT,1.0f)
+		DEF_GET_TE_STATE(F32,F32,getGlow,0.0f)
+		DEF_GET_TE_STATE(LLTextureEntry::e_texgen,LLTextureEntry::e_texgen,getTexGen,LLTextureEntry::TEX_GEN_DEFAULT)
+		DEF_GET_TE_STATE(LLColor4,const LLColor4&,getColor,LLColor4::white)		
+	};
 };
 
 #endif
+
diff --git a/indra/newview/llphysicsmotion.cpp b/indra/newview/llphysicsmotion.cpp
index 3ee0746412f826b37ac211cebc4237bdde72b5a7..18b85cc9c3bc4796bbddd69b4902c72a1be5741d 100755
--- a/indra/newview/llphysicsmotion.cpp
+++ b/indra/newview/llphysicsmotion.cpp
@@ -428,13 +428,13 @@ F32 LLPhysicsMotion::toLocal(const LLVector3 &world)
 F32 LLPhysicsMotion::calculateVelocity_local()
 {
 	const F32 world_to_model_scale = 100.0f;
-	LLJoint *joint = mJointState->getJoint();
-	const LLVector3 position_world = joint->getWorldPosition();
-	const LLVector3 last_position_world = mPosition_world;
+        LLJoint *joint = mJointState->getJoint();
+        const LLVector3 position_world = joint->getWorldPosition();
+        const LLVector3 last_position_world = mPosition_world;
 	const LLVector3 positionchange_world = (position_world-last_position_world) * world_to_model_scale;
-	const LLVector3 velocity_world = positionchange_world;
-	const F32 velocity_local = toLocal(velocity_world);
-	return velocity_local;
+        const LLVector3 velocity_world = positionchange_world;
+        const F32 velocity_local = toLocal(velocity_world);
+        return velocity_local;
 }
 
 F32 LLPhysicsMotion::calculateAcceleration_local(const F32 velocity_local)
diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp
index 4681efd3e5901335ca04f36ce61ac7d1ef1b8d38..0cbdbe16a39342d21726d44e689536afdc9cce48 100755
--- a/indra/newview/llselectmgr.cpp
+++ b/indra/newview/llselectmgr.cpp
@@ -29,6 +29,7 @@
 // file include
 #define LLSELECTMGR_CPP
 #include "llselectmgr.h"
+#include "llmaterialmgr.h"
 
 // library includes
 #include "llcachename.h"
@@ -103,7 +104,6 @@ const F32 SILHOUETTE_UPDATE_THRESHOLD_SQUARED = 0.02f;
 const S32 MAX_ACTION_QUEUE_SIZE = 20;
 const S32 MAX_SILS_PER_FRAME = 50;
 const S32 MAX_OBJECTS_PER_PACKET = 254;
-const S32 TE_SELECT_MASK_ALL = 0xFFFFFFFF;
 
 //
 // Globals
@@ -188,6 +188,7 @@ LLSelectMgr::LLSelectMgr()
    mDebugSelectMgr(LLCachedControl<bool>(gSavedSettings, "DebugSelectMgr", FALSE))
 {
 	mTEMode = FALSE;
+	mTextureChannel = LLRender::DIFFUSE_MAP;
 	mLastCameraPos.clearVec();
 
 	sHighlightThickness	= gSavedSettings.getF32("SelectionHighlightThickness");
@@ -236,6 +237,8 @@ void LLSelectMgr::clearSelections()
 	mHighlightedObjects->deleteAllNodes();
 	mRectSelectedObjects.clear();
 	mGridObjects.deleteAllNodes();
+
+	LLPipeline::setRenderHighlightTextureChannel(LLRender::DIFFUSE_MAP);
 }
 
 void LLSelectMgr::update()
@@ -815,6 +818,7 @@ void LLSelectMgr::addAsFamily(std::vector<LLViewerObject*>& objects, BOOL add_to
 			if (objectp->getNumTEs() > 0)
 			{
 				nodep->selectAllTEs(TRUE);
+				objectp->setAllTESelected(true);
 			}
 			else
 			{
@@ -843,6 +847,10 @@ void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, BOOL undoab
 	// check to see if object is already in list
 	LLSelectNode *nodep = mSelectedObjects->findNode(objectp);
 
+	// Reset (in anticipation of being set to an appropriate value by panel refresh, if they're up)
+	//
+	setTextureChannel(LLRender::DIFFUSE_MAP);
+
 	// if not in list, add it
 	if (!nodep)
 	{
@@ -872,10 +880,12 @@ void LLSelectMgr::addAsIndividual(LLViewerObject *objectp, S32 face, BOOL undoab
 	else if (face == SELECT_ALL_TES)
 	{
 		nodep->selectAllTEs(TRUE);
+		objectp->setAllTESelected(true);
 	}
 	else if (0 <= face && face < SELECT_MAX_TES)
 	{
 		nodep->selectTE(face, TRUE);
+		objectp->setTESelected(face, true);
 	}
 	else
 	{
@@ -1095,6 +1105,7 @@ LLObjectSelectionHandle LLSelectMgr::selectHighlightedObjects()
 
 		// flag this object as selected
 		objectp->setSelected(TRUE);
+		objectp->setAllTESelected(true);
 
 		mSelectedObjects->mSelectType = getSelectTypeForObject(objectp);
 
@@ -1318,6 +1329,7 @@ void LLSelectMgr::remove(LLViewerObject *objectp, S32 te, BOOL undoable)
 		if (nodep->isTESelected(te))
 		{
 			nodep->selectTE(te, FALSE);
+			objectp->setTESelected(te, false);
 		}
 		else
 		{
@@ -2004,6 +2016,76 @@ void LLSelectMgr::selectionSetGlow(F32 glow)
 	mSelectedObjects->applyToObjects( &func2 );
 }
 
+void LLSelectMgr::selectionSetMaterialParams(LLSelectedTEMaterialFunctor* material_func)
+{
+	struct f1 : public LLSelectedTEFunctor
+	{
+		LLMaterialPtr mMaterial;
+		f1(LLSelectedTEMaterialFunctor* material_func) : _material_func(material_func) {}
+
+		bool apply(LLViewerObject* object, S32 face)
+		{
+			if (object && object->permModify() && _material_func)
+			{
+				LLTextureEntry* tep = object->getTE(face);
+				if (tep)
+				{
+					LLMaterialPtr current_material = tep->getMaterialParams();
+					_material_func->apply(object, face, tep, current_material);
+				}
+			}
+			return true;
+		}
+
+		LLSelectedTEMaterialFunctor* _material_func;
+	} func1(material_func);
+	mSelectedObjects->applyToTEs( &func1 );
+
+	struct f2 : public LLSelectedObjectFunctor
+	{
+		virtual bool apply(LLViewerObject* object)
+		{
+			if (object->permModify())
+			{
+				object->sendTEUpdate();
+			}
+			return true;
+		}
+	} func2;
+	mSelectedObjects->applyToObjects( &func2 );
+}
+
+void LLSelectMgr::selectionRemoveMaterial()
+{
+	struct f1 : public LLSelectedTEFunctor
+	{
+		bool apply(LLViewerObject* object, S32 face)
+		{
+			if (object->permModify())
+			{
+			        LL_DEBUGS("Materials") << "Removing material from object " << object->getID() << " face " << face << LL_ENDL;
+				LLMaterialMgr::getInstance()->remove(object->getID(),face);
+				object->setTEMaterialParams(face, NULL);
+			}
+			return true;
+		}
+	} func1;
+	mSelectedObjects->applyToTEs( &func1 );
+
+	struct f2 : public LLSelectedObjectFunctor
+	{
+		virtual bool apply(LLViewerObject* object)
+		{
+			if (object->permModify())
+			{
+				object->sendTEUpdate();
+			}
+			return true;
+		}
+	} func2;
+	mSelectedObjects->applyToObjects( &func2 );
+}
+
 
 //-----------------------------------------------------------------------------
 // findObjectPermissions()
@@ -2425,19 +2507,66 @@ void LLSelectMgr::adjustTexturesByScale(BOOL send_to_sim, BOOL stretch)
 					continue;
 				}
 				
-				LLVector3 scale_ratio = selectNode->mTextureScaleRatios[te_num]; 
 				LLVector3 object_scale = object->getScale();
+				LLVector3 diffuse_scale_ratio  = selectNode->mTextureScaleRatios[te_num]; 
+
+				// We like these to track together. NORSPEC-96
+				//
+				LLVector3 normal_scale_ratio   = diffuse_scale_ratio; 
+				LLVector3 specular_scale_ratio = diffuse_scale_ratio; 
 				
 				// Apply new scale to face
 				if (planar)
 				{
-					object->setTEScale(te_num, 1.f/object_scale.mV[s_axis]*scale_ratio.mV[s_axis],
-										1.f/object_scale.mV[t_axis]*scale_ratio.mV[t_axis]);
+					F32 diffuse_scale_s = diffuse_scale_ratio.mV[s_axis]/object_scale.mV[s_axis];
+					F32 diffuse_scale_t = diffuse_scale_ratio.mV[t_axis]/object_scale.mV[t_axis];
+
+					F32 normal_scale_s = normal_scale_ratio.mV[s_axis]/object_scale.mV[s_axis];
+					F32 normal_scale_t = normal_scale_ratio.mV[t_axis]/object_scale.mV[t_axis];
+
+					F32 specular_scale_s = specular_scale_ratio.mV[s_axis]/object_scale.mV[s_axis];
+					F32 specular_scale_t = specular_scale_ratio.mV[t_axis]/object_scale.mV[t_axis];
+
+					object->setTEScale(te_num, diffuse_scale_s, diffuse_scale_t);
+
+					LLTextureEntry* tep = object->getTE(te_num);
+
+					if (tep && !tep->getMaterialParams().isNull())
+					{
+						LLMaterialPtr orig = tep->getMaterialParams();
+						LLMaterialPtr p = new LLMaterial(orig->asLLSD());
+						p->setNormalRepeat(normal_scale_s, normal_scale_t);
+						p->setSpecularRepeat(specular_scale_s, specular_scale_t);
+
+						LLMaterialMgr::getInstance()->put(object->getID(), te_num, *p);
+					}
 				}
 				else
 				{
-					object->setTEScale(te_num, scale_ratio.mV[s_axis]*object_scale.mV[s_axis],
-											scale_ratio.mV[t_axis]*object_scale.mV[t_axis]);
+
+					F32 diffuse_scale_s = diffuse_scale_ratio.mV[s_axis]*object_scale.mV[s_axis];
+					F32 diffuse_scale_t = diffuse_scale_ratio.mV[t_axis]*object_scale.mV[t_axis];
+
+					F32 normal_scale_s = normal_scale_ratio.mV[s_axis]*object_scale.mV[s_axis];
+					F32 normal_scale_t = normal_scale_ratio.mV[t_axis]*object_scale.mV[t_axis];
+
+					F32 specular_scale_s = specular_scale_ratio.mV[s_axis]*object_scale.mV[s_axis];
+					F32 specular_scale_t = specular_scale_ratio.mV[t_axis]*object_scale.mV[t_axis];
+
+					object->setTEScale(te_num, diffuse_scale_s,diffuse_scale_t);
+
+					LLTextureEntry* tep = object->getTE(te_num);
+
+					if (tep && !tep->getMaterialParams().isNull())
+					{
+						LLMaterialPtr orig = tep->getMaterialParams();
+
+						LLMaterialPtr p = new LLMaterial(orig->asLLSD());
+						p->setNormalRepeat(normal_scale_s, normal_scale_t);
+						p->setSpecularRepeat(specular_scale_s, specular_scale_t);
+
+						LLMaterialMgr::getInstance()->put(object->getID(), te_num, *p);
+					}
 				}
 				send = send_to_sim;
 			}
@@ -4398,7 +4527,8 @@ void LLSelectMgr::saveSelectedObjectTransform(EActionType action_type)
 	struct f : public LLSelectedNodeFunctor
 	{
 		EActionType mActionType;
-		f(EActionType a) : mActionType(a) {}
+		LLSelectMgr* mManager;
+		f(EActionType a, LLSelectMgr* p) : mActionType(a), mManager(p) {}
 		virtual bool apply(LLSelectNode* selectNode)
 		{
 			LLViewerObject*	object = selectNode->getObject();
@@ -4445,10 +4575,10 @@ void LLSelectMgr::saveSelectedObjectTransform(EActionType action_type)
 			}
 		
 			selectNode->mSavedScale = object->getScale();
-			selectNode->saveTextureScaleRatios();
+			selectNode->saveTextureScaleRatios(mManager->mTextureChannel);			
 			return true;
 		}
-	} func(action_type);
+	} func(action_type, this);
 	getSelection()->applyToNodes(&func);	
 	
 	mSavedSelectionBBox = getBBoxOfSelection();
@@ -5759,36 +5889,43 @@ void LLSelectNode::saveTextures(const uuid_vec_t& textures)
 	}
 }
 
-void LLSelectNode::saveTextureScaleRatios()
+void LLSelectNode::saveTextureScaleRatios(LLRender::eTexIndex index_to_query)
 {
 	mTextureScaleRatios.clear();
+
 	if (mObject.notNull())
 	{
+		
+		LLVector3 scale = mObject->getScale();
+
 		for (U8 i = 0; i < mObject->getNumTEs(); i++)
 		{
-			F32 s,t;
+			F32 diffuse_s = 1.0f;
+			F32 diffuse_t = 1.0f;
+			
+			LLVector3 v;
 			const LLTextureEntry* tep = mObject->getTE(i);
-			tep->getScale(&s,&t);
-			U32 s_axis = 0;
-			U32 t_axis = 0;
+			if (!tep)
+				continue;
 
+			U32 s_axis = VX;
+			U32 t_axis = VY;
 			LLPrimitive::getTESTAxes(i, &s_axis, &t_axis);
 
-			LLVector3 v;
-			LLVector3 scale = mObject->getScale();
-
+			tep->getScale(&diffuse_s,&diffuse_t);
+			
 			if (tep->getTexGen() == LLTextureEntry::TEX_GEN_PLANAR)
 			{
-				v.mV[s_axis] = s*scale.mV[s_axis];
-				v.mV[t_axis] = t*scale.mV[t_axis];
+				v.mV[s_axis] = diffuse_s*scale.mV[s_axis];
+				v.mV[t_axis] = diffuse_t*scale.mV[t_axis];
+				mTextureScaleRatios.push_back(v);
 			}
 			else
 			{
-				v.mV[s_axis] = s/scale.mV[s_axis];
-				v.mV[t_axis] = t/scale.mV[t_axis];
-			}
-
-			mTextureScaleRatios.push_back(v);
+				v.mV[s_axis] = diffuse_s/scale.mV[s_axis];
+				v.mV[t_axis] = diffuse_t/scale.mV[t_axis];
+				mTextureScaleRatios.push_back(v);
+			}			
 		}
 	}
 }
diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h
index cc78e358691dcb5b6f6f3138d3874a4278c24fd5..d4b736640c0947cbb2125d60d584dbe8599d8e08 100755
--- a/indra/newview/llselectmgr.h
+++ b/indra/newview/llselectmgr.h
@@ -43,10 +43,12 @@
 #include "llpermissions.h"
 #include "llcontrol.h"
 #include "llviewerobject.h"	// LLObjectSelection::getSelectedTEValue template
+#include "llmaterial.h"
 
 #include <deque>
 #include <boost/iterator/filter_iterator.hpp>
 #include <boost/signals2.hpp>
+#include <boost/make_shared.hpp>	// boost::make_shared
 
 class LLMessageSystem;
 class LLViewerTexture;
@@ -83,6 +85,12 @@ struct LLSelectedTEFunctor
 	virtual bool apply(LLViewerObject* object, S32 face) = 0;
 };
 
+struct LLSelectedTEMaterialFunctor
+{
+	virtual ~LLSelectedTEMaterialFunctor() {};
+	virtual LLMaterialPtr apply(LLViewerObject* object, S32 face, LLTextureEntry* tep, LLMaterialPtr& current_material) = 0;
+};
+
 template <typename T> struct LLSelectedTEGetFunctor
 {
 	virtual ~LLSelectedTEGetFunctor() {};
@@ -121,6 +129,8 @@ typedef enum e_selection_type
 	SELECT_TYPE_HUD
 }ESelectType;
 
+const S32 TE_SELECT_MASK_ALL = 0xFFFFFFFF;
+
 // Contains information about a selected object, particularly which TEs are selected.
 class LLSelectNode
 {
@@ -143,7 +153,7 @@ class LLSelectNode
 	// *NOTE: invalidate stored textures and colors when # faces change
 	void saveColors();
 	void saveTextures(const uuid_vec_t& textures);
-	void saveTextureScaleRatios();
+	void saveTextureScaleRatios(LLRender::eTexIndex index_to_query);
 
 	BOOL allowOperationOnNode(PermissionBit op, U64 group_proxy_power) const;
 
@@ -510,6 +520,11 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton<LLSelectMgr>
 	void saveSelectedObjectColors();
 	void saveSelectedObjectTextures();
 
+	// Sets which texture channel to query for scale and rot of display
+	// and depends on UI state of LLPanelFace when editing
+	void setTextureChannel(LLRender::eTexIndex texIndex) { mTextureChannel = texIndex; }
+	LLRender::eTexIndex getTextureChannel() { return mTextureChannel; }
+
 	void selectionUpdatePhysics(BOOL use_physics);
 	void selectionUpdateTemporary(BOOL is_temporary);
 	void selectionUpdatePhantom(BOOL is_ghost);
@@ -540,6 +555,8 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton<LLSelectMgr>
 	void selectionSetClickAction(U8 action);
 	void selectionSetIncludeInSearch(bool include_in_search);
 	void selectionSetGlow(const F32 glow);
+	void selectionSetMaterialParams(LLSelectedTEMaterialFunctor* material_func);
+	void selectionRemoveMaterial();
 
 	void selectionSetObjectPermissions(U8 perm_field, BOOL set, U32 perm_mask, BOOL override = FALSE);
 	void selectionSetObjectName(const std::string& name);
@@ -771,6 +788,7 @@ class LLSelectMgr : public LLEditMenuHandler, public LLSingleton<LLSelectMgr>
 	EGridMode				mGridMode;
 
 	BOOL					mTEMode;			// render te
+	LLRender::eTexIndex	mTextureChannel; // diff, norm, or spec, depending on UI editing mode
 	LLVector3d				mSelectionCenterGlobal;
 	LLBBox					mSelectionBBox;
 
diff --git a/indra/newview/llsidepanelappearance.cpp b/indra/newview/llsidepanelappearance.cpp
index 74fa5a87bba7b96cf49046ce58da33e501b2bf49..df413ab849aee3ebc3e3f713da1e3b51170ca3e6 100755
--- a/indra/newview/llsidepanelappearance.cpp
+++ b/indra/newview/llsidepanelappearance.cpp
@@ -231,7 +231,7 @@ void LLSidepanelAppearance::updateToVisibility(const LLSD &new_visibility)
 		{
 			gAgentCamera.changeCameraToDefault();
 			gAgentCamera.resetView();
-		}	
+		}
 	}
 }
 
diff --git a/indra/newview/llsidepanelappearance.h b/indra/newview/llsidepanelappearance.h
index 762f557a8004e471b1a9f9b14a255e3f0817ff17..b0a6b9cf916da7107891a817d2132f965c4afc17 100755
--- a/indra/newview/llsidepanelappearance.h
+++ b/indra/newview/llsidepanelappearance.h
@@ -47,7 +47,7 @@ class LLSidepanelAppearance : public LLPanel
 	virtual ~LLSidepanelAppearance();
 
 	/*virtual*/ BOOL postBuild();
-	/*virtual*/ void onOpen(const LLSD& key);	
+	/*virtual*/ void onOpen(const LLSD& key);
 
 	void refreshCurrentOutfitName(const std::string& name = "");
 
diff --git a/indra/newview/llspatialpartition.cpp b/indra/newview/llspatialpartition.cpp
index f85e855fd3a87549da2ee1faecc14906daf024f2..941c5787835c61a42d80a9ca2488a357e321423e 100755
--- a/indra/newview/llspatialpartition.cpp
+++ b/indra/newview/llspatialpartition.cpp
@@ -1498,6 +1498,8 @@ BOOL LLSpatialGroup::rebound()
 	if (mOctreeNode->getChildCount() == 1 && mOctreeNode->getElementCount() == 0)
 	{
 		LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0);
+
+		//rebound single child
 		group->rebound();
 		
 		//copy single child's bounding box
@@ -1506,10 +1508,11 @@ BOOL LLSpatialGroup::rebound()
 		mExtents[0] = group->mExtents[0];
 		mExtents[1] = group->mExtents[1];
 		
+		//treat this node as a "chute" to a deeper level of the tree
 		group->setState(SKIP_FRUSTUM_CHECK);
 	}
 	else if (mOctreeNode->isLeaf())
-	{ //copy object bounding box if this is a leaf
+	{ //copy object bounding box if this is a leaf 
 		boundObjects(TRUE, mExtents[0], mExtents[1]);
 		mBounds[0] = mObjectBounds[0];
 		mBounds[1] = mObjectBounds[1];
@@ -1518,14 +1521,17 @@ BOOL LLSpatialGroup::rebound()
 	{
 		LLVector4a& newMin = mExtents[0];
 		LLVector4a& newMax = mExtents[1];
+		
+		//get bounding box of first child
 		LLSpatialGroup* group = (LLSpatialGroup*) mOctreeNode->getChild(0)->getListener(0);
 		group->clearState(SKIP_FRUSTUM_CHECK);
 		group->rebound();
+
 		//initialize to first child
 		newMin = group->mExtents[0];
 		newMax = group->mExtents[1];
 
-		//first, rebound children
+		//rebound remaining children, expanding bounding box to encompass children
 		for (U32 i = 1; i < mOctreeNode->getChildCount(); i++)
 		{
 			group = (LLSpatialGroup*) mOctreeNode->getChild(i)->getListener(0);
@@ -2506,7 +2512,7 @@ void pushBufferVerts(LLVertexBuffer* buffer, U32 mask)
 	}
 }
 
-void pushBufferVerts(LLSpatialGroup* group, U32 mask)
+void pushBufferVerts(LLSpatialGroup* group, U32 mask, bool push_alpha = true)
 {
 	if (group->mSpatialPartition->mRenderByGroup)
 	{
@@ -2515,7 +2521,10 @@ void pushBufferVerts(LLSpatialGroup* group, U32 mask)
 			LLDrawInfo* params = *(group->mDrawMap.begin()->second.begin());
 			LLRenderPass::applyModelMatrix(*params);
 		
-			pushBufferVerts(group->mVertexBuffer, mask);
+			if (push_alpha)
+			{
+				pushBufferVerts(group->mVertexBuffer, mask);
+			}
 
 			for (LLSpatialGroup::buffer_map_t::iterator i = group->mBufferMap.begin(); i != group->mBufferMap.end(); ++i)
 			{
@@ -2529,10 +2538,10 @@ void pushBufferVerts(LLSpatialGroup* group, U32 mask)
 			}
 		}
 	}
-	else
+	/*else
 	{
-		drawBox(group->mBounds[0], group->mBounds[1]);
-	}
+		//drawBox(group->mBounds[0], group->mBounds[1]);
+	}*/
 }
 
 void pushVertsColorCoded(LLSpatialGroup* group, U32 mask)
@@ -2705,17 +2714,53 @@ void renderOctree(LLSpatialGroup* group)
 //	drawBoxOutline(LLVector3(node->getCenter()), LLVector3(node->getSize()));
 }
 
+std::set<LLSpatialGroup*> visible_selected_groups;
+
 void renderVisibility(LLSpatialGroup* group, LLCamera* camera)
 {
-	LLGLEnable blend(GL_BLEND);
+	/*LLGLEnable blend(GL_BLEND);
 	gGL.setSceneBlendType(LLRender::BT_ALPHA);
 	LLGLEnable cull(GL_CULL_FACE);
-	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);*/
 
-	BOOL render_objects = (!LLPipeline::sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && group->isVisible() &&
+	/*BOOL render_objects = (!LLPipeline::sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && group->isVisible() &&
 							!group->isEmpty();
 
+
 	if (render_objects)
+	{
+		LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+
+		LLGLDisable blend(GL_BLEND);
+		gGL.diffuseColor4f(0.f, 0.75f, 0.f,0.5f);
+		pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX, false);
+		
+		glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+		glLineWidth(4.f);
+		gGL.diffuseColor4f(0.f, 0.5f, 0.f, 1.f);
+		pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX, false);
+		glLineWidth(1.f);
+		glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+
+		bool selected = false;
+		
+		for (LLSpatialGroup::element_iter iter = group->getDataBegin(); iter != group->getDataEnd(); ++iter)
+		{
+			LLDrawable* drawable = *iter;
+			if (drawable->getVObj().notNull() && drawable->getVObj()->isSelected())
+			{
+				selected = true;
+				break;
+			}
+		}
+		
+		if (selected)
+		{ //store for rendering occlusion volume as overlay
+			visible_selected_groups.insert(group);
+		}
+	}*/		
+
+	/*if (render_objects)
 	{
 		LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER);
 		gGL.diffuseColor4f(0, 0.5f, 0, 0.5f);
@@ -2740,6 +2785,59 @@ void renderVisibility(LLSpatialGroup* group, LLCamera* camera)
 			gGL.diffuseColor4f(0.f, 0.75f, 0.f,0.5f);
 			gGL.diffuseColor4f(0.f, 0.75f, 0.f, 0.5f);
 			pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX);
+		
+			bool selected = false;
+		
+			for (LLSpatialGroup::element_iter iter = group->getDataBegin(); iter != group->getDataEnd(); ++iter)
+			{
+				LLDrawable* drawable = *iter;
+				if (drawable->getVObj().notNull() && drawable->getVObj()->isSelected())
+				{
+					selected = true;
+					break;
+				}
+			}
+		
+			if (selected)
+			{ //store for rendering occlusion volume as overlay
+				visible_selected_groups.insert(group);
+			}
+		}		
+	}*/
+}
+
+void renderXRay(LLSpatialGroup* group, LLCamera* camera)
+{
+	BOOL render_objects = (!LLPipeline::sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) && group->isVisible() &&
+							!group->isEmpty();
+	
+	if (render_objects)
+	{
+		pushBufferVerts(group, LLVertexBuffer::MAP_VERTEX, false);
+
+		bool selected = false;
+
+		for (LLSpatialGroup::element_iter iter = group->getDataBegin(); iter != group->getDataEnd(); ++iter)
+		{
+			LLDrawable* drawable = *iter;
+			if (drawable->getVObj().notNull() && drawable->getVObj()->isSelected())
+			{
+				selected = true;
+				break;
+			}
+		}
+
+		if (selected)
+		{ //store for rendering occlusion volume as overlay
+
+			if (!group->mSpatialPartition->isBridge())
+			{
+				visible_selected_groups.insert(group);
+			}
+			else
+			{
+				visible_selected_groups.insert(group->mSpatialPartition->asBridge()->getSpatialGroup());
+			}
 		}
 	}
 }
@@ -3039,9 +3137,9 @@ void renderNormals(LLDrawable* drawablep)
 				gGL.vertex3fv(face.mPositions[j].getF32ptr());
 				gGL.vertex3fv(p.getF32ptr());
 				
-				if (face.mBinormals)
+				if (face.mTangents)
 				{
-					n.setMul(face.mBinormals[j], scale);
+					n.setMul(face.mTangents[j], scale);
 					p.setAdd(face.mPositions[j], n);
 				
 					gGL.diffuseColor4f(0,1,1,1);
@@ -3888,11 +3986,17 @@ void renderRaycast(LLDrawable* drawablep)
 					gGL.translatef(trans.mV[0], trans.mV[1], trans.mV[2]);					
 					gGL.multMatrix((F32*) vobj->getRelativeXform().mMatrix);
 
-					LLVector3 start, end;
+					LLVector4a start, end;
 					if (transform)
 					{
-						start = vobj->agentPositionToVolume(gDebugRaycastStart);
-						end = vobj->agentPositionToVolume(gDebugRaycastEnd);
+						LLVector3 v_start(gDebugRaycastStart.getF32ptr());
+						LLVector3 v_end(gDebugRaycastEnd.getF32ptr());
+
+						v_start = vobj->agentPositionToVolume(v_start);
+						v_end = vobj->agentPositionToVolume(v_end);
+
+						start.load3(v_start.mV);
+						end.load3(v_end.mV);
 					}
 					else
 					{
@@ -3900,11 +4004,8 @@ void renderRaycast(LLDrawable* drawablep)
 						end = gDebugRaycastEnd;
 					}
 
-					LLVector4a starta, enda;
-					starta.load3(start.mV);
-					enda.load3(end.mV);
 					LLVector4a dir;
-					dir.setSub(enda, starta);
+					dir.setSub(end, start);
 
 					gGL.flush();
 					glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);				
@@ -3927,7 +4028,7 @@ void renderRaycast(LLDrawable* drawablep)
 							((LLVolumeFace*) &face)->createOctree(); 
 						}
 
-						LLRenderOctreeRaycast render(starta, dir, &t);
+						LLRenderOctreeRaycast render(start, dir, &t);
 					
 						render.traverse(face.mOctree);
 					}
@@ -3952,10 +4053,18 @@ void renderRaycast(LLDrawable* drawablep)
 			// draw intersection point
 			gGL.pushMatrix();
 			gGL.loadMatrix(gGLModelView);
-			LLVector3 translate = gDebugRaycastIntersection;
+			LLVector3 translate(gDebugRaycastIntersection.getF32ptr());
 			gGL.translatef(translate.mV[0], translate.mV[1], translate.mV[2]);
 			LLCoordFrame orient;
-			orient.lookDir(gDebugRaycastNormal, gDebugRaycastBinormal);
+			LLVector4a debug_binormal;
+			
+			debug_binormal.setCross3(gDebugRaycastNormal, gDebugRaycastTangent);
+			debug_binormal.mul(gDebugRaycastTangent.getF32ptr()[3]);
+
+			LLVector3 normal(gDebugRaycastNormal.getF32ptr());
+			LLVector3 binormal(debug_binormal.getF32ptr());
+						
+			orient.lookDir(normal, binormal);
 			LLMatrix4 rotation;
 			orient.getRotMatrixToParent(rotation);
 			gGL.multMatrix((float*)rotation.mMatrix);
@@ -4199,6 +4308,48 @@ class LLOctreeRenderNonOccluded : public LLOctreeTraveler<LLDrawable>
 	}
 };
 
+class LLOctreeRenderXRay : public LLOctreeTraveler<LLDrawable>
+{
+public:
+	LLCamera* mCamera;
+	LLOctreeRenderXRay(LLCamera* camera): mCamera(camera) {}
+	
+	virtual void traverse(const LLSpatialGroup::OctreeNode* node)
+	{
+		LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+		
+		if (!mCamera || mCamera->AABBInFrustumNoFarClip(group->mBounds[0], group->mBounds[1]))
+		{
+			node->accept(this);
+			stop_glerror();
+
+			for (U32 i = 0; i < node->getChildCount(); i++)
+			{
+				traverse(node->getChild(i));
+				stop_glerror();
+			}
+			
+			//render visibility wireframe
+			if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
+			{
+				group->rebuildGeom();
+				group->rebuildMesh();
+
+				gGL.flush();
+				gGL.pushMatrix();
+				gGLLastMatrix = NULL;
+				gGL.loadMatrix(gGLModelView);
+				renderXRay(group, mCamera);
+				stop_glerror();
+				gGLLastMatrix = NULL;
+				gGL.popMatrix();
+			}
+		}
+	}
+
+	virtual void visit(const LLSpatialGroup::OctreeNode* node) {}
+
+};
 
 class LLOctreeRenderPhysicsShapes : public LLOctreeTraveler<LLDrawable>
 {
@@ -4426,6 +4577,26 @@ void LLSpatialPartition::renderDebug()
 	LLOctreeRenderNonOccluded render_debug(camera);
 	render_debug.traverse(mOctree);
 
+
+	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
+	{
+		{
+			LLGLEnable cull(GL_CULL_FACE);
+			
+			LLGLEnable blend(GL_BLEND);
+			LLGLDepthTest depth_under(GL_TRUE, GL_FALSE, GL_GREATER);
+			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+			gGL.diffuseColor4f(0.5f, 0.0f, 0, 0.25f);
+
+			LLGLEnable offset(GL_POLYGON_OFFSET_LINE);
+			glPolygonOffset(-1.f, -1.f);
+
+			LLOctreeRenderXRay xray(camera);
+			xray.traverse(mOctree);
+
+			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+		}
+	}
 	if (LLGLSLShader::sNoFixedFunction)
 	{
 		gDebugProgram.unbind();
@@ -4457,28 +4628,30 @@ BOOL LLSpatialPartition::isVisible(const LLVector3& v)
 	return TRUE;
 }
 
+LL_ALIGN_PREFIX(16)
 class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler
 {
 public:
-	LLVector3 mStart;
-	LLVector3 mEnd;
+	LL_ALIGN_16(LLVector4a mStart);
+	LL_ALIGN_16(LLVector4a mEnd);
+
 	S32       *mFaceHit;
-	LLVector3 *mIntersection;
+	LLVector4a *mIntersection;
 	LLVector2 *mTexCoord;
-	LLVector3 *mNormal;
-	LLVector3 *mBinormal;
+	LLVector4a *mNormal;
+	LLVector4a *mTangent;
 	LLDrawable* mHit;
 	BOOL mPickTransparent;
 
-	LLOctreeIntersect(LLVector3 start, LLVector3 end, BOOL pick_transparent,
-					  S32* face_hit, LLVector3* intersection, LLVector2* tex_coord, LLVector3* normal, LLVector3* binormal)
+	LLOctreeIntersect(const LLVector4a& start, const LLVector4a& end, BOOL pick_transparent,
+					  S32* face_hit, LLVector4a* intersection, LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent)
 		: mStart(start),
 		  mEnd(end),
 		  mFaceHit(face_hit),
 		  mIntersection(intersection),
 		  mTexCoord(tex_coord),
 		  mNormal(normal),
-		  mBinormal(binormal),
+		  mTangent(tangent),
 		  mHit(NULL),
 		  mPickTransparent(pick_transparent)
 	{
@@ -4509,23 +4682,22 @@ class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler
 			size = group->mBounds[1];
 			center = group->mBounds[0];
 			
-			LLVector3 local_start = mStart;
-			LLVector3 local_end   = mEnd;
+			LLVector4a local_start = mStart;
+			LLVector4a local_end   = mEnd;
 
 			if (group->mSpatialPartition->isBridge())
 			{
 				LLMatrix4 local_matrix = group->mSpatialPartition->asBridge()->mDrawable->getRenderMatrix();
 				local_matrix.invert();
-				
-				local_start = mStart * local_matrix;
-				local_end   = mEnd   * local_matrix;
-			}
 
-			LLVector4a start, end;
-			start.load3(local_start.mV);
-			end.load3(local_end.mV);
+				LLMatrix4a local_matrix4a;
+				local_matrix4a.loadu(local_matrix);
 
-			if (LLLineSegmentBoxIntersect(start, end, center, size))
+				local_matrix4a.affineTransform(mStart, local_start);
+				local_matrix4a.affineTransform(mEnd, local_end);
+			}
+
+			if (LLLineSegmentBoxIntersect(local_start, local_end, center, size))
 			{
 				check(child);
 			}
@@ -4556,14 +4728,14 @@ class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler
 
 			if (vobj)
 			{
-				LLVector3 intersection;
+				LLVector4a intersection;
 				bool skip_check = false;
 				if (vobj->isAvatar())
 				{
 					LLVOAvatar* avatar = (LLVOAvatar*) vobj;
 					if (avatar->isSelf() && LLFloater::isVisible(gFloaterTools))
 					{
-						LLViewerObject* hit = avatar->lineSegmentIntersectRiggedAttachments(mStart, mEnd, -1, mPickTransparent, mFaceHit, &intersection, mTexCoord, mNormal, mBinormal);
+						LLViewerObject* hit = avatar->lineSegmentIntersectRiggedAttachments(mStart, mEnd, -1, mPickTransparent, mFaceHit, &intersection, mTexCoord, mNormal, mTangent);
 						if (hit)
 						{
 							mEnd = intersection;
@@ -4579,7 +4751,7 @@ class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler
 					}
 				}
 
-				if (!skip_check && vobj->lineSegmentIntersect(mStart, mEnd, -1, mPickTransparent, mFaceHit, &intersection, mTexCoord, mNormal, mBinormal))
+				if (!skip_check && vobj->lineSegmentIntersect(mStart, mEnd, -1, mPickTransparent, mFaceHit, &intersection, mTexCoord, mNormal, mTangent))
 				{
 					mEnd = intersection;  // shorten ray so we only find CLOSER hits
 					if (mIntersection)
@@ -4594,19 +4766,19 @@ class LLOctreeIntersect : public LLSpatialGroup::OctreeTraveler
 				
 		return false;
 	}
-};
+} LL_ALIGN_POSTFIX(16);
 
-LLDrawable* LLSpatialPartition::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
+LLDrawable* LLSpatialPartition::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
 													 BOOL pick_transparent,													
 													 S32* face_hit,                   // return the face hit
-													 LLVector3* intersection,         // return the intersection point
+													 LLVector4a* intersection,         // return the intersection point
 													 LLVector2* tex_coord,            // return the texture coordinates of the intersection point
-													 LLVector3* normal,               // return the surface normal at the intersection point
-													 LLVector3* bi_normal             // return the surface bi-normal at the intersection point
+													 LLVector4a* normal,               // return the surface normal at the intersection point
+													 LLVector4a* tangent			// return the surface tangent at the intersection point
 	)
 
 {
-	LLOctreeIntersect intersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, bi_normal);
+	LLOctreeIntersect intersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, tangent);
 	LLDrawable* drawable = intersect.check(mOctree);
 
 	return drawable;
@@ -4632,7 +4804,13 @@ LLDrawInfo::LLDrawInfo(U16 start, U16 end, U32 count, U32 offset,
 	mGroup(NULL),
 	mFace(NULL),
 	mDistance(0.f),
-	mDrawMode(LLRender::TRIANGLES)
+	mDrawMode(LLRender::TRIANGLES),
+	mMaterial(NULL),
+	mShaderMask(0),
+	mSpecColor(1.0f, 1.0f, 1.0f, 0.5f),
+	mEnvIntensity(0.0f),
+	mAlphaMaskCutoff(0.5f),
+	mDiffuseAlphaMode(0)
 {
 	mVertexBuffer->validateRange(mStart, mEnd, mCount, mOffset);
 	
diff --git a/indra/newview/llspatialpartition.h b/indra/newview/llspatialpartition.h
index b1706d9d35130dbb75970c09c64761d6688ae2dd..9732be90af7be9541e5ef0324d324742b638f06a 100755
--- a/indra/newview/llspatialpartition.h
+++ b/indra/newview/llspatialpartition.h
@@ -112,6 +112,7 @@ class LLDrawInfo : public LLRefCount
 	U32 mOffset;
 	BOOL mFullbright;
 	U8 mBump;
+	U8 mShiny;
 	BOOL mParticle;
 	F32 mPartSize;
 	F32 mVSize;
@@ -119,6 +120,18 @@ class LLDrawInfo : public LLRefCount
 	LL_ALIGN_16(LLFace* mFace); //associated face
 	F32 mDistance;
 	U32 mDrawMode;
+	LLMaterialPtr mMaterial; // If this is null, the following parameters are unused.
+	LLMaterialID mMaterialID;
+	U32 mShaderMask;
+	LLPointer<LLViewerTexture> mSpecularMap;
+	const LLMatrix4* mSpecularMapMatrix;
+	LLPointer<LLViewerTexture> mNormalMap;
+	const LLMatrix4* mNormalMapMatrix;
+	LLVector4 mSpecColor; // XYZ = Specular RGB, W = Specular Exponent
+	F32  mEnvIntensity;
+	F32  mAlphaMaskCutoff;
+	U8   mDiffuseAlphaMode;
+
 
 	struct CompareTexture
 	{
@@ -169,7 +182,7 @@ class LLDrawInfo : public LLRefCount
 		}
 
 	};
-
+	
 	struct CompareBump
 	{
 		bool operator()(const LLPointer<LLDrawInfo>& lhs, const LLPointer<LLDrawInfo>& rhs) 
@@ -191,7 +204,7 @@ class LLDrawInfo : public LLRefCount
 	};
 };
 
-LL_ALIGN_PREFIX(16)
+LL_ALIGN_PREFIX(64)
 class LLSpatialGroup : public LLOctreeListener<LLDrawable>
 {
 	friend class LLSpatialPartition;
@@ -477,13 +490,13 @@ class LLSpatialPartition: public LLGeometryManager
 	LLSpatialGroup *put(LLDrawable *drawablep, BOOL was_visible = FALSE);
 	BOOL remove(LLDrawable *drawablep, LLSpatialGroup *curp);
 	
-	LLDrawable* lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
+	LLDrawable* lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
 									 BOOL pick_transparent, 
 									 S32* face_hit,                          // return the face hit
-									 LLVector3* intersection = NULL,         // return the intersection point
+									 LLVector4a* intersection = NULL,         // return the intersection point
 									 LLVector2* tex_coord = NULL,            // return the texture coordinates of the intersection point
-									 LLVector3* normal = NULL,               // return the surface normal at the intersection point
-									 LLVector3* bi_normal = NULL             // return the surface bi-normal at the intersection point
+									 LLVector4a* normal = NULL,               // return the surface normal at the intersection point
+									 LLVector4a* tangent = NULL             // return the surface tangent at the intersection point
 		);
 	
 	
@@ -739,7 +752,7 @@ class LLVolumeGeometryManager: public LLGeometryManager
 	virtual void rebuildGeom(LLSpatialGroup* group);
 	virtual void rebuildMesh(LLSpatialGroup* group);
 	virtual void getGeometry(LLSpatialGroup* group);
-	void genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort = FALSE, BOOL batch_textures = FALSE);
+	void genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort = FALSE, BOOL batch_textures = FALSE, BOOL no_materials = FALSE);
 	void registerFace(LLSpatialGroup* group, LLFace* facep, U32 type);
 };
 
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 82596a86b9f3b5f486eb2543ea17828ab0ade2d1..cff3a7e02ac2491d5fed9e21d7c6175f9a14f988 100755
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -645,7 +645,7 @@ bool idle_startup()
 				gAudiop = (LLAudioEngine *) new LLAudioEngine_OpenAL();
 			}
 #endif
-            
+
 			if (gAudiop)
 			{
 #if LL_WINDOWS
diff --git a/indra/newview/lltextureatlas.cpp b/indra/newview/lltextureatlas.cpp
index f8c1bca8aed1097696f9609a5ce6040487ad2683..dbbe331954e9d98378b27981d2cf8328ed2ebd22 100755
--- a/indra/newview/lltextureatlas.cpp
+++ b/indra/newview/lltextureatlas.cpp
@@ -71,7 +71,7 @@ LLTextureAtlas::~LLTextureAtlas()
 //virtual 
 S8 LLTextureAtlas::getType() const
 {
-	return LLViewerTexture::ATLAS_TEXTURE ;
+	return 0; //LLViewerTexture::ATLAS_TEXTURE ;
 }
 
 void LLTextureAtlas::getTexCoordOffset(S16 col, S16 row, F32& xoffset, F32& yoffset)
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index 305f6fca0f71a49487c9bc10a4a9c29a44d2887f..36a7aeb59024078a8fd7e74f5fb25e374a82c05b 100755
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -568,8 +568,11 @@ bool LLTextureCacheRemoteWorker::doWrite()
 			idx = mCache->setHeaderCacheEntry(mID, entry, mImageSize, mDataSize); // create the new entry.
 			if(idx >= 0)
 			{
-				//write to the fast cache.
-				llassert_always(mCache->writeToFastCache(idx, mRawImage, mRawDiscardLevel));
+				// (almost always) write to the fast cache.
+				if (mRawImage->getDataSize())
+				{
+					llassert_always(mCache->writeToFastCache(idx, mRawImage, mRawDiscardLevel));
+				}
 			}
 		}
 		else
@@ -1895,10 +1898,17 @@ LLPointer<LLImageRaw> LLTextureCache::readFromFastCache(const LLUUID& id, S32& d
 bool LLTextureCache::writeToFastCache(S32 id, LLPointer<LLImageRaw> raw, S32 discardlevel)
 {
 	//rescale image if needed
+	if (raw.isNull() || !raw->getData())
+	{
+		llerrs << "Attempted to write NULL raw image to fastcache" << llendl;
+		return false;
+	}
+
 	S32 w, h, c;
 	w = raw->getWidth();
 	h = raw->getHeight();
 	c = raw->getComponents();
+
 	S32 i = 0 ;
 	
 	while(((w >> i) * (h >> i) * c) > TEXTURE_FAST_CACHE_ENTRY_SIZE - TEXTURE_FAST_CACHE_ENTRY_OVERHEAD)
diff --git a/indra/newview/lltexturecache.h b/indra/newview/lltexturecache.h
index e3fc957fd264b65651c0ce0fbf9ba65b01b45d1a..deaacc49759552f30d9f5e6777b0f833148e1010 100755
--- a/indra/newview/lltexturecache.h
+++ b/indra/newview/lltexturecache.h
@@ -24,7 +24,7 @@
  * $/LicenseInfo$
  */
 
-#ifndef LL_LLTEXTURECACHE_
+#ifndef LL_LLTEXTURECACHE_H
 #define LL_LLTEXTURECACHE_H
 
 #include "lldir.h"
diff --git a/indra/newview/lltexturectrl.cpp b/indra/newview/lltexturectrl.cpp
index e2d0fdf3576579558378b1d947ad45019ccd992f..4676f7b251327f250d4a38e73d259559637732d9 100755
--- a/indra/newview/lltexturectrl.cpp
+++ b/indra/newview/lltexturectrl.cpp
@@ -144,7 +144,7 @@ class LLFloaterTexturePicker : public LLFloater
 	static void		onBtnCancel( void* userdata );
 		   void		onBtnPipette( );
 	//static void		onBtnRevert( void* userdata );
-	static void		onBtnWhite( void* userdata );
+	static void		onBtnBlank( void* userdata );
 	static void		onBtnNone( void* userdata );
 	static void		onBtnClear( void* userdata );
 		   void		onSelectionChange(const std::deque<LLFolderViewItem*> &items, BOOL user_action);
@@ -165,7 +165,6 @@ class LLFloaterTexturePicker : public LLFloater
 	LLUUID				mImageAssetID; // Currently selected texture
 	LLUIImagePtr		mFallbackImage; // What to show if currently selected texture is null.
 
-	LLUUID				mWhiteImageAssetID;
 	LLUUID				mSpecialCurrentImageAssetID;  // Used when the asset id has no corresponding texture in the user's inventory.
 	LLUUID				mOriginalImageAssetID;
 
@@ -208,8 +207,7 @@ LLFloaterTexturePicker::LLFloaterTexturePicker(
 :	LLFloater(LLSD()),
 	mOwner( owner ),
 	mImageAssetID( owner->getImageAssetID() ),
-	mFallbackImage( fallback_image ),
-	mWhiteImageAssetID( gSavedSettings.getString( "UIImgWhiteUUID" ) ),
+	mFallbackImage( fallback_image ),	
 	mOriginalImageAssetID(owner->getImageAssetID()),
 	mLabel(label),
 	mTentativeLabel(NULL),
@@ -426,7 +424,7 @@ BOOL LLFloaterTexturePicker::postBuild()
 
 	childSetAction("Default",LLFloaterTexturePicker::onBtnSetToDefault,this);
 	childSetAction("None", LLFloaterTexturePicker::onBtnNone,this);
-	childSetAction("Blank", LLFloaterTexturePicker::onBtnWhite,this);
+	childSetAction("Blank", LLFloaterTexturePicker::onBtnBlank,this);
 
 
 	childSetCommitCallback("show_folders_check", onShowFolders, this);
@@ -581,7 +579,7 @@ void LLFloaterTexturePicker::draw()
 		}
 
 		getChildView("Default")->setEnabled(mImageAssetID != mOwner->getDefaultImageAssetID());
-		getChildView("Blank")->setEnabled(mImageAssetID != mWhiteImageAssetID );
+		getChildView("Blank")->setEnabled(mImageAssetID != mOwner->getBlankImageAssetID());
 		getChildView("None")->setEnabled(mOwner->getAllowNoTexture() && !mImageAssetID.isNull() );
 
 		LLFloater::draw();
@@ -721,11 +719,11 @@ void LLFloaterTexturePicker::onBtnSetToDefault(void* userdata)
 }
 
 // static
-void LLFloaterTexturePicker::onBtnWhite(void* userdata)
+void LLFloaterTexturePicker::onBtnBlank(void* userdata)
 {
 	LLFloaterTexturePicker* self = (LLFloaterTexturePicker*) userdata;
 	self->setCanApply(true, true);
-	self->setImageID( self->mWhiteImageAssetID );
+	self->setImageID( self->mOwner->getBlankImageAssetID() );
 	self->commitIfImmediateSet();
 }
 
@@ -1042,6 +1040,7 @@ LLTextureCtrl::LLTextureCtrl(const LLTextureCtrl::Params& p)
 	mDragCallback(NULL),
 	mDropCallback(NULL),
 	mOnCancelCallback(NULL),
+	mOnCloseCallback(NULL),
 	mOnSelectCallback(NULL),
 	mBorderColor( p.border_color() ),
 	mAllowNoTexture( FALSE ),
@@ -1056,6 +1055,12 @@ LLTextureCtrl::LLTextureCtrl(const LLTextureCtrl::Params& p)
 	mDefaultImageName(p.default_image_name),
 	mFallbackImage(p.fallback_image)
 {
+
+	// Default of defaults is white image for diff tex
+	//
+	LLUUID whiteImage( gSavedSettings.getString( "UIImgWhiteUUID" ) );
+	setBlankImageAssetID( whiteImage );
+
 	setAllowNoTexture(p.allow_no_texture);
 	setCanApplyImmediately(p.can_apply_immediately);
 	mCommitOnSelection = !p.no_commit_on_selection;
@@ -1292,6 +1297,10 @@ void LLTextureCtrl::onFloaterClose()
 
 	if (floaterp)
 	{
+		if (mOnCloseCallback)
+		{
+			mOnCloseCallback(this,LLSD());
+		}
 		floaterp->setOwner(NULL);
 	}
 
diff --git a/indra/newview/lltexturectrl.h b/indra/newview/lltexturectrl.h
index 599d9c70c521e656efabeb1ad12febb0b41094d1..ad79042ef161a86839c5ca83954f71b2301ea844 100755
--- a/indra/newview/lltexturectrl.h
+++ b/indra/newview/lltexturectrl.h
@@ -126,6 +126,7 @@ class LLTextureCtrl
 
 	// LLTextureCtrl interface
 	void			showPicker(BOOL take_focus);
+	bool			isPickerShown() { return !mFloaterHandle.isDead(); }
 	void			setLabel(const std::string& label);
 	void			setLabelWidth(S32 label_width) {mLabelWidth =label_width;}	
 	const std::string&	getLabel() const							{ return mLabel; }
@@ -145,6 +146,9 @@ class LLTextureCtrl
 
 	const std::string&	getDefaultImageName() const					{ return mDefaultImageName; }
 
+	void			setBlankImageAssetID( const LLUUID& id )	{ mBlankImageAssetID = id; }
+	const LLUUID&	getBlankImageAssetID() const { return mBlankImageAssetID; }
+
 	void			setCaption(const std::string& caption);
 	void			setCanApplyImmediately(BOOL b);
 
@@ -174,7 +178,7 @@ class LLTextureCtrl
 	void setDropCallback(drag_n_drop_callback cb)	{ mDropCallback = cb; }
 	
 	void setOnCancelCallback(commit_callback_t cb)	{ mOnCancelCallback = cb; }
-	
+	void setOnCloseCallback(commit_callback_t cb)	{ mOnCloseCallback = cb; }
 	void setOnSelectCallback(commit_callback_t cb)	{ mOnSelectCallback = cb; }
 
 	/*
@@ -195,12 +199,14 @@ class LLTextureCtrl
 	drag_n_drop_callback	 	mDropCallback;
 	commit_callback_t		 	mOnCancelCallback;
 	commit_callback_t		 	mOnSelectCallback;
+	commit_callback_t		 	mOnCloseCallback;
 	texture_selected_callback	mOnTextureSelectedCallback;
 	LLPointer<LLViewerFetchedTexture> mTexturep;
 	LLUIColor				 	mBorderColor;
 	LLUUID					 	mImageItemID;
 	LLUUID					 	mImageAssetID;
 	LLUUID					 	mDefaultImageAssetID;
+	LLUUID					 	mBlankImageAssetID;
 	LLUIImagePtr				mFallbackImage;
 	std::string					mDefaultImageName;
 	LLHandle<LLFloater>			mFloaterHandle;
diff --git a/indra/newview/lltexturefetch.cpp b/indra/newview/lltexturefetch.cpp
index bf9d803098f08b58ace07cccdd446f5e827fed32..141198bc163f3b17db807a7a86138e1a7f7e80d1 100755
--- a/indra/newview/lltexturefetch.cpp
+++ b/indra/newview/lltexturefetch.cpp
@@ -1896,9 +1896,9 @@ void LLTextureFetchWorker::onCompleted(LLCore::HttpHandle handle, LLCore::HttpRe
 	LLCore::HttpStatus status(response->getStatus());
 	
 	LL_DEBUGS("Texture") << "HTTP COMPLETE: " << mID
-						 << " status: " << status.toHex()
-						 << " '" << status.toString() << "'"
-						 << llendl;
+			 << " status: " << status.toHex()
+			 << " '" << status.toString() << "'"
+			 << llendl;
 //	unsigned int offset(0), length(0), full_length(0);
 //	response->getRange(&offset, &length, &full_length);
 // 	llwarns << "HTTP COMPLETE: " << mID << " handle: " << handle
diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp
index 094694dc06164737928f2d762adc23d46b68aacd..3da934b1486786b3a441473d95a700bf81b84fb8 100755
--- a/indra/newview/llvieweraudio.cpp
+++ b/indra/newview/llvieweraudio.cpp
@@ -400,7 +400,7 @@ void audio_update_volume(bool force_update)
 		gAudiop->setDopplerFactor(gSavedSettings.getF32("AudioLevelDoppler"));
 
 		if(!LLViewerCamera::getInstance()->cameraUnderWater())
-			gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelRolloff"));
+		gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelRolloff"));
 		else
 			gAudiop->setRolloffFactor(gSavedSettings.getF32("AudioLevelUnderwaterRolloff"));
 
@@ -494,18 +494,18 @@ void audio_update_wind(bool force_update)
 	LLViewerRegion* region = gAgent.getRegion();
 	if (region)
 	{
-		// Scale down the contribution of weather-simulation wind to the
-		// ambient wind noise.  Wind velocity averages 3.5 m/s, with gusts to 7 m/s
-		// whereas steady-state avatar walk velocity is only 3.2 m/s.
-		// Without this the world feels desolate on first login when you are
-		// standing still.
-		static LLUICachedControl<F32> wind_level("AudioLevelWind", 0.5f);
-		LLVector3 scaled_wind_vec = gWindVec * wind_level;
-
-		// Mix in the avatar's motion, subtract because when you walk north,
-		// the apparent wind moves south.
-		LLVector3 final_wind_vec = scaled_wind_vec - gAgent.getVelocity();
-
+        // Scale down the contribution of weather-simulation wind to the
+        // ambient wind noise.  Wind velocity averages 3.5 m/s, with gusts to 7 m/s
+        // whereas steady-state avatar walk velocity is only 3.2 m/s.
+        // Without this the world feels desolate on first login when you are
+        // standing still.
+        static LLUICachedControl<F32> wind_level("AudioLevelWind", 0.5f);
+        LLVector3 scaled_wind_vec = gWindVec * wind_level;
+        
+        // Mix in the avatar's motion, subtract because when you walk north,
+        // the apparent wind moves south.
+        LLVector3 final_wind_vec = scaled_wind_vec - gAgent.getVelocity();
+        
 		// rotate the wind vector to be listener (agent) relative
 		gRelativeWindVec = gAgent.getFrameAgent().rotateToLocal( final_wind_vec );
 
diff --git a/indra/newview/llviewercontrol.cpp b/indra/newview/llviewercontrol.cpp
index a62f73deef0e2b373f14efb8a682473ab8f6fd3d..afbb59e72343e2ea05404adc93d9f097d432e790 100755
--- a/indra/newview/llviewercontrol.cpp
+++ b/indra/newview/llviewercontrol.cpp
@@ -401,6 +401,25 @@ static bool handleRenderDeferredChanged(const LLSD& newvalue)
 	return true;
 }
 
+// This looks a great deal like handleRenderDeferredChanged because
+// Advanced Lighting (Materials) implies bumps and shiny so disabling
+// bumps should further disable that feature.
+//
+static bool handleRenderBumpChanged(const LLSD& newval)
+{
+	LLRenderTarget::sUseFBO = newval.asBoolean();
+	if (gPipeline.isInit())
+	{
+		gPipeline.updateRenderBump();
+		gPipeline.updateRenderDeferred();
+		gPipeline.releaseGLBuffers();
+		gPipeline.createGLBuffers();
+		gPipeline.resetVertexBuffers();
+		LLViewerShaderMgr::instance()->setShaders();
+	}
+	return true;
+}
+
 static bool handleRenderUseImpostorsChanged(const LLSD& newvalue)
 {
 	LLVOAvatar::sUseImpostors = newvalue.asBoolean();
@@ -629,7 +648,7 @@ void settings_setup_listeners()
 	gSavedSettings.getControl("RenderDebugTextureBind")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
 	gSavedSettings.getControl("RenderAutoMaskAlphaDeferred")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
 	gSavedSettings.getControl("RenderAutoMaskAlphaNonDeferred")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
-	gSavedSettings.getControl("RenderObjectBump")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
+	gSavedSettings.getControl("RenderObjectBump")->getSignal()->connect(boost::bind(&handleRenderBumpChanged, _2));
 	gSavedSettings.getControl("RenderMaxVBOSize")->getSignal()->connect(boost::bind(&handleResetVertexBuffersChanged, _2));
 	gSavedSettings.getControl("RenderDeferredNoise")->getSignal()->connect(boost::bind(&handleReleaseGLBufferChanged, _2));
 	gSavedSettings.getControl("RenderUseImpostors")->getSignal()->connect(boost::bind(&handleRenderUseImpostorsChanged, _2));
diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp
index cf59e679551fbfaa939697420b40190b0ed35b97..f90b35a7bddbf65cbe7897110678c795c1262c53 100755
--- a/indra/newview/llviewerdisplay.cpp
+++ b/indra/newview/llviewerdisplay.cpp
@@ -98,6 +98,7 @@ BOOL gDepthDirty = FALSE;
 BOOL gResizeScreenTexture = FALSE;
 BOOL gWindowResized = FALSE;
 BOOL gSnapshot = FALSE;
+BOOL gShaderProfileFrame = FALSE;
 
 U32 gRecentFrameCount = 0; // number of 'recent' frames
 LLFrameTimer gRecentFPSTime;
@@ -114,7 +115,8 @@ void render_disconnected_background();
 
 void display_startup()
 {
-	if (   !gViewerWindow->getActive()
+	if (   !gViewerWindow
+		|| !gViewerWindow->getActive()
 		|| !gViewerWindow->getWindow()->getVisible() 
 		|| gViewerWindow->getWindow()->getMinimized() )
 	{
@@ -125,7 +127,14 @@ void display_startup()
 
 	// Update images?
 	//gImageList.updateImages(0.01f);
-	LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName();
+	
+	// Written as branch to appease GCC which doesn't like different
+	// pointer types across ternary ops
+	//
+	if (!LLViewerFetchedTexture::sWhiteImagep.isNull())
+	{
+		LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName();
+	}
 
 	LLGLSDefault gls_default;
 
@@ -147,10 +156,12 @@ void display_startup()
 	LLGLSUIDefault gls_ui;
 	gPipeline.disableLights();
 
+	if (gViewerWindow)
 	gViewerWindow->setup2DRender();
 	gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
 
 	gGL.color4f(1,1,1,1);
+	if (gViewerWindow)
 	gViewerWindow->draw();
 	gGL.flush();
 
@@ -159,7 +170,9 @@ void display_startup()
 	LLGLState::checkStates();
 	LLGLState::checkTextureChannels();
 
+	if (gViewerWindow && gViewerWindow->getWindow())
 	gViewerWindow->getWindow()->swapBuffers();
+
 	glClear(GL_DEPTH_BUFFER_BIT);
 }
 
@@ -340,6 +353,12 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		return;
 	}
 
+
+	if (gShaderProfileFrame)
+	{
+		LLGLSLShader::initProfile();
+	}
+
 	//LLGLState::verify(FALSE);
 
 	/////////////////////////////////////////////////
@@ -654,6 +673,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 
 		static LLCullResult result;
 		LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+		LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE;
 		gPipeline.updateCull(*LLViewerCamera::getInstance(), result, water_clip);
 		stop_glerror();
 
@@ -860,7 +880,7 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 		//}
 
 		LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? TRUE : FALSE;
-		
+
 		LLGLState::checkStates();
 		LLGLState::checkClientArrays();
 
@@ -1018,6 +1038,12 @@ void display(BOOL rebuild, F32 zoom_factor, int subfield, BOOL for_snapshot)
 	LLAppViewer::instance()->pingMainloopTimeout("Display:Done");
 
 	gShiftFrame = false;
+
+	if (gShaderProfileFrame)
+	{
+		gShaderProfileFrame = FALSE;
+		LLGLSLShader::finishProfile();
+	}
 }
 
 void render_hud_attachments()
@@ -1037,6 +1063,7 @@ void render_hud_attachments()
 
 	if (LLPipeline::sShowHUDAttachments && !gDisconnected && setup_hud_matrices())
 	{
+		LLPipeline::sRenderingHUDs = TRUE;
 		LLCamera hud_cam = *LLViewerCamera::getInstance();
 		hud_cam.setOrigin(-1.f,0,0);
 		hud_cam.setAxes(LLVector3(1,0,0), LLVector3(0,1,0), LLVector3(0,0,1));
@@ -1081,10 +1108,13 @@ void render_hud_attachments()
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_SIMPLE);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_VOLUME);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA);
+		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_ALPHA_MASK);
+		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_FULLBRIGHT_ALPHA_MASK);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_FULLBRIGHT);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_BUMP);
+		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_MATERIAL);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK);
 		gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY);
@@ -1109,6 +1139,7 @@ void render_hud_attachments()
 			gPipeline.toggleRenderDebugFeature((void*) LLPipeline::RENDER_DEBUG_FEATURE_UI);
 		}
 		LLPipeline::sUseOcclusion = use_occlusion;
+		LLPipeline::sRenderingHUDs = FALSE;
 	}
 	gGL.matrixMode(LLRender::MM_PROJECTION);
 	gGL.popMatrix();
diff --git a/indra/newview/llviewerinventory.h b/indra/newview/llviewerinventory.h
index 61b1b8d84651ce46f6c54dbc722d0730c229e208..ab19a12014f7948484c0c5f298facc4f2e28352f 100755
--- a/indra/newview/llviewerinventory.h
+++ b/indra/newview/llviewerinventory.h
@@ -256,7 +256,7 @@ class AddFavoriteLandmarkCallback : public LLInventoryCallback
 public:
 	AddFavoriteLandmarkCallback() : mTargetLandmarkId(LLUUID::null) {}
 	void setTargetLandmarkId(const LLUUID& target_uuid) { mTargetLandmarkId = target_uuid; }
-
+	
 private:
 	void fire(const LLUUID& inv_item);
 
@@ -283,13 +283,13 @@ class LLBoostFuncInventoryCallback: public LLInventoryCallback
 
 	// virtual
 	void fire(const LLUUID& item_id)
-	{
+{
 		mFireFunc(item_id);
 	}
 
 	// virtual
 	~LLBoostFuncInventoryCallback()
-	{
+{
 		mDestroyFunc();
 	}
 	
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index beca08203fdd5aa3b85f59c84ad50e27dfdc5fa4..5e2f05f4687297dabc2e9dd8156f1ae925d28fab 100755
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -147,6 +147,8 @@ void handle_test_load_url(void*);
 //extern BOOL gDebugAvatarRotation;
 extern BOOL gDebugClicks;
 extern BOOL gDebugWindowProc;
+extern BOOL gShaderProfileFrame;
+
 //extern BOOL gDebugTextEditorTips;
 //extern BOOL gDebugSelectMgr;
 
@@ -291,6 +293,7 @@ void request_friendship(const LLUUID& agent_id);
 
 // Tools menu
 void handle_selected_texture_info(void*);
+void handle_selected_material_info();
 
 void handle_dump_followcam(void*);
 void handle_viewer_enable_message_log(void*);
@@ -1189,28 +1192,6 @@ class LLAdvancedCheckWireframe : public view_listener_t
 	}
 };
 	
-//////////////////////
-// TEXTURE ATLAS //
-//////////////////////
-
-class LLAdvancedToggleTextureAtlas : public view_listener_t
-{
-	bool handleEvent(const LLSD& userdata)
-	{
-		LLViewerTexture::sUseTextureAtlas = !LLViewerTexture::sUseTextureAtlas;
-		gSavedSettings.setBOOL("EnableTextureAtlas", LLViewerTexture::sUseTextureAtlas) ;
-		return true;
-	}
-};
-
-class LLAdvancedCheckTextureAtlas : public view_listener_t
-{
-	bool handleEvent(const LLSD& userdata)
-	{
-		bool new_value = LLViewerTexture::sUseTextureAtlas; // <-- make this using LLCacheControl
-		return new_value;
-	}
-};
 
 //////////////////////////
 // DUMP SCRIPTED CAMERA //
@@ -6463,7 +6444,7 @@ class LLAttachmentDetachFromPoint : public view_listener_t
 				LLViewerObject *attached_object = (*iter);
 				ids_to_remove.push_back(attached_object->getAttachmentItemID());
 			}
-		}
+			}
 		if (!ids_to_remove.empty())
 		{
 			LLAppearanceMgr::instance().removeItemsFromAvatar(ids_to_remove);
@@ -6920,6 +6901,47 @@ void handle_selected_texture_info(void*)
 	}
 }
 
+void handle_selected_material_info()
+{
+	for (LLObjectSelection::valid_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_begin();
+		iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++)
+	{
+		LLSelectNode* node = *iter;
+		
+		std::string msg;
+		msg.assign("Material info for: \n");
+		msg.append(node->mName);
+		
+		U8 te_count = node->getObject()->getNumTEs();
+		// map from material ID to list of faces using it
+		typedef std::map<LLMaterialID, std::vector<U8> > map_t;
+		map_t faces_per_material;
+		for (U8 i = 0; i < te_count; i++)
+		{
+			if (!node->isTESelected(i)) continue;
+	
+			const LLMaterialID& material_id = node->getObject()->getTE(i)->getMaterialID();
+			faces_per_material[material_id].push_back(i);
+		}
+		// Per-material, dump which faces are using it.
+		map_t::iterator it;
+		for (it = faces_per_material.begin(); it != faces_per_material.end(); ++it)
+		{
+			const LLMaterialID& material_id = it->first;
+			msg += llformat("%s on face ", material_id.asString().c_str());
+			for (U8 i = 0; i < it->second.size(); ++i)
+			{
+				msg.append( llformat("%d ", (S32)(it->second[i])));
+			}
+			msg.append("\n");
+		}
+
+		LLSD args;
+		args["MESSAGE"] = msg;
+		LLNotificationsUtil::add("SystemMessage", args);
+	}
+}
+
 void handle_test_male(void*)
 {
 	LLAppearanceMgr::instance().wearOutfitByName("Male Shape & Outfit");
@@ -7022,6 +7044,15 @@ class LLAdvancedClickRenderShadowOption: public view_listener_t
 	}
 };
 
+class LLAdvancedClickRenderProfile: public view_listener_t
+{
+	bool handleEvent(const LLSD& userdata)
+	{
+		gShaderProfileFrame = TRUE;
+		return true;
+	}
+};
+
 void menu_toggle_attached_lights(void* user_data)
 {
 	LLPipeline::sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights");
@@ -8442,11 +8473,10 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLAdvancedToggleInfoDisplay(), "Advanced.ToggleInfoDisplay");
 	view_listener_t::addMenu(new LLAdvancedCheckInfoDisplay(), "Advanced.CheckInfoDisplay");
 	view_listener_t::addMenu(new LLAdvancedSelectedTextureInfo(), "Advanced.SelectedTextureInfo");
+	commit.add("Advanced.SelectedMaterialInfo", boost::bind(&handle_selected_material_info));
 	view_listener_t::addMenu(new LLAdvancedToggleWireframe(), "Advanced.ToggleWireframe");
 	view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe");
 	// Develop > Render
-	view_listener_t::addMenu(new LLAdvancedToggleTextureAtlas(), "Advanced.ToggleTextureAtlas");
-	view_listener_t::addMenu(new LLAdvancedCheckTextureAtlas(), "Advanced.CheckTextureAtlas");
 	view_listener_t::addMenu(new LLAdvancedEnableObjectObjectOcclusion(), "Advanced.EnableObjectObjectOcclusion");
 	view_listener_t::addMenu(new LLAdvancedEnableRenderFBO(), "Advanced.EnableRenderFBO");
 	view_listener_t::addMenu(new LLAdvancedEnableRenderDeferred(), "Advanced.EnableRenderDeferred");
@@ -8460,7 +8490,7 @@ void initialize_menus()
 	view_listener_t::addMenu(new LLAdvancedHandleAttachedLightParticles(), "Advanced.HandleAttachedLightParticles");
 	view_listener_t::addMenu(new LLAdvancedCheckRenderShadowOption(), "Advanced.CheckRenderShadowOption");
 	view_listener_t::addMenu(new LLAdvancedClickRenderShadowOption(), "Advanced.ClickRenderShadowOption");
-	
+	view_listener_t::addMenu(new LLAdvancedClickRenderProfile(), "Advanced.ClickRenderProfile");
 
 	#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
 	view_listener_t::addMenu(new LLAdvancedHandleToggleHackedGodmode(), "Advanced.HandleToggleHackedGodmode");
diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp
index 064e96e3942905e6ca72a51440438565ad4c8587..6f7b2f40e62d999240141820e4886f60ba45d3b4 100755
--- a/indra/newview/llviewerobject.cpp
+++ b/indra/newview/llviewerobject.cpp
@@ -201,6 +201,8 @@ LLViewerObject::LLViewerObject(const LLUUID &id, const LLPCode pcode, LLViewerRe
 	mTotalCRC(0),
 	mListIndex(-1),
 	mTEImages(NULL),
+	mTENormalMaps(NULL),
+	mTESpecularMaps(NULL),
 	mGLName(0),
 	mbCanSelect(TRUE),
 	mFlags(0),
@@ -321,6 +323,18 @@ void LLViewerObject::deleteTEImages()
 {
 	delete[] mTEImages;
 	mTEImages = NULL;
+	
+	if (mTENormalMaps != NULL)
+	{
+		delete[] mTENormalMaps;
+		mTENormalMaps = NULL;
+	}
+	
+	if (mTESpecularMaps != NULL)
+	{
+		delete[] mTESpecularMaps;
+		mTESpecularMaps = NULL;
+	}	
 }
 
 void LLViewerObject::markDead()
@@ -516,6 +530,17 @@ void LLViewerObject::setNameValueList(const std::string& name_value_list)
 	}
 }
 
+void LLViewerObject::setSelected(BOOL sel)
+{
+	mUserSelected = sel;
+	resetRot();
+
+	if (!sel)
+	{
+		setAllTESelected(false);
+	}
+}
+
 // This method returns true if the object is over land owned by the
 // agent.
 bool LLViewerObject::isReturnable()
@@ -3796,19 +3821,19 @@ LLViewerObject* LLViewerObject::getRootEdit() const
 }
 
 
-BOOL LLViewerObject::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
+BOOL LLViewerObject::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
 										  S32 face,
 										  BOOL pick_transparent,
 										  S32* face_hit,
-										  LLVector3* intersection,
+										  LLVector4a* intersection,
 										  LLVector2* tex_coord,
-										  LLVector3* normal,
-										  LLVector3* bi_normal)
+										  LLVector4a* normal,
+										  LLVector4a* tangent)
 {
 	return false;
 }
 
-BOOL LLViewerObject::lineSegmentBoundingBox(const LLVector3& start, const LLVector3& end)
+BOOL LLViewerObject::lineSegmentBoundingBox(const LLVector4a& start, const LLVector4a& end)
 {
 	if (mDrawable.isNull() || mDrawable->isDead())
 	{
@@ -3825,11 +3850,7 @@ BOOL LLViewerObject::lineSegmentBoundingBox(const LLVector3& start, const LLVect
 	size.setSub(ext[1], ext[0]);
 	size.mul(0.5f);
 
-	LLVector4a starta, enda;
-	starta.load3(start.mV);
-	enda.load3(end.mV);
-
-	return LLLineSegmentBoxIntersect(starta, enda, center, size);
+	return LLLineSegmentBoxIntersect(start, end, center, size);
 }
 
 U8 LLViewerObject::getMediaType() const
@@ -3928,25 +3949,39 @@ void LLViewerObject::setNumTEs(const U8 num_tes)
 		{
 			LLPointer<LLViewerTexture> *new_images;
 			new_images = new LLPointer<LLViewerTexture>[num_tes];
+			
+			LLPointer<LLViewerTexture> *new_normmaps;
+			new_normmaps = new LLPointer<LLViewerTexture>[num_tes];
+			
+			LLPointer<LLViewerTexture> *new_specmaps;
+			new_specmaps = new LLPointer<LLViewerTexture>[num_tes];
 			for (i = 0; i < num_tes; i++)
 			{
 				if (i < getNumTEs())
 				{
 					new_images[i] = mTEImages[i];
+					new_normmaps[i] = mTENormalMaps[i];
+					new_specmaps[i] = mTESpecularMaps[i];
 				}
 				else if (getNumTEs())
 				{
 					new_images[i] = mTEImages[getNumTEs()-1];
+					new_normmaps[i] = mTENormalMaps[getNumTEs()-1];
+					new_specmaps[i] = mTESpecularMaps[getNumTEs()-1];
 				}
 				else
 				{
 					new_images[i] = NULL;
+					new_normmaps[i] = NULL;
+					new_specmaps[i] = NULL;
 				}
 			}
 
 			deleteTEImages();
 			
 			mTEImages = new_images;
+			mTENormalMaps = new_normmaps;
+			mTESpecularMaps = new_specmaps;
 		}
 		else
 		{
@@ -4025,12 +4060,18 @@ void LLViewerObject::sendTEUpdate() const
 void LLViewerObject::setTE(const U8 te, const LLTextureEntry &texture_entry)
 {
 	LLPrimitive::setTE(te, texture_entry);
-//  This doesn't work, don't get any textures.
-//	if (mDrawable.notNull() && mDrawable->isVisible())
-//	{
-		const LLUUID& image_id = getTE(te)->getID();
+
+	const LLUUID& image_id = getTE(te)->getID();
 		mTEImages[te] = LLViewerTextureManager::getFetchedTexture(image_id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
-//	}
+	
+	if (getTE(te)->getMaterialParams().notNull())
+	{
+		const LLUUID& norm_id = getTE(te)->getMaterialParams()->getNormalID();
+		mTENormalMaps[te] = LLViewerTextureManager::getFetchedTexture(norm_id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
+		
+		const LLUUID& spec_id = getTE(te)->getMaterialParams()->getSpecularID();
+		mTESpecularMaps[te] = LLViewerTextureManager::getFetchedTexture(spec_id, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE);
+	}
 }
 
 void LLViewerObject::setTEImage(const U8 te, LLViewerTexture *imagep)
@@ -4065,6 +4106,52 @@ S32 LLViewerObject::setTETextureCore(const U8 te, LLViewerTexture *image)
 	return retval;
 }
 
+S32 LLViewerObject::setTENormalMapCore(const U8 te, LLViewerTexture *image)
+{
+	S32 retval = TEM_CHANGE_TEXTURE;
+	const LLUUID& uuid = image ? image->getID() : LLUUID::null;
+	if (uuid != getTE(te)->getID() ||
+		uuid == LLUUID::null)
+	{
+		LLTextureEntry* tep = getTE(te);
+		LLMaterial* mat = NULL;
+		if (tep)
+		{
+		   mat = tep->getMaterialParams();
+		}
+
+		if (mat)
+		{
+			mat->setNormalID(uuid);
+		}
+	}
+	changeTENormalMap(te,image);	
+	return retval;
+}
+
+S32 LLViewerObject::setTESpecularMapCore(const U8 te, LLViewerTexture *image)
+{
+	S32 retval = TEM_CHANGE_TEXTURE;
+	const LLUUID& uuid = image ? image->getID() : LLUUID::null;
+	if (uuid != getTE(te)->getID() ||
+		uuid == LLUUID::null)
+	{
+		LLTextureEntry* tep = getTE(te);
+		LLMaterial* mat = NULL;
+		if (tep)
+		{
+			mat = tep->getMaterialParams();
+		}
+
+		if (mat)
+		{
+			mat->setSpecularID(uuid);
+		}		
+	}
+	changeTESpecularMap(te, image);
+	return retval;
+}
+
 //virtual
 void LLViewerObject::changeTEImage(S32 index, LLViewerTexture* new_image) 
 {
@@ -4075,6 +4162,26 @@ void LLViewerObject::changeTEImage(S32 index, LLViewerTexture* new_image)
 	mTEImages[index] = new_image ;
 }
 
+void LLViewerObject::changeTENormalMap(S32 index, LLViewerTexture* new_image)
+{
+	if(index < 0 || index >= getNumTEs())
+	{
+		return ;
+	}
+	mTENormalMaps[index] = new_image ;
+	refreshMaterials();
+}
+
+void LLViewerObject::changeTESpecularMap(S32 index, LLViewerTexture* new_image)
+{
+	if(index < 0 || index >= getNumTEs())
+	{
+		return ;
+	}
+	mTESpecularMaps[index] = new_image ;
+	refreshMaterials();
+}
+
 S32 LLViewerObject::setTETexture(const U8 te, const LLUUID& uuid)
 {
 	// Invalid host == get from the agent's sim
@@ -4083,6 +4190,19 @@ S32 LLViewerObject::setTETexture(const U8 te, const LLUUID& uuid)
 	return setTETextureCore(te,image);
 }
 
+S32 LLViewerObject::setTENormalMap(const U8 te, const LLUUID& uuid)
+{
+	LLViewerFetchedTexture *image = (uuid == LLUUID::null) ? NULL : LLViewerTextureManager::getFetchedTexture(
+		uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost::invalid);
+	return setTENormalMapCore(te, image);
+}
+
+S32 LLViewerObject::setTESpecularMap(const U8 te, const LLUUID& uuid)
+{
+	LLViewerFetchedTexture *image = (uuid == LLUUID::null) ? NULL : LLViewerTextureManager::getFetchedTexture(
+		uuid, FTT_DEFAULT, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, LLHost::invalid);
+	return setTESpecularMapCore(te, image);
+}
 
 S32 LLViewerObject::setTEColor(const U8 te, const LLColor3& color)
 {
@@ -4243,6 +4363,61 @@ S32 LLViewerObject::setTEGlow(const U8 te, const F32 glow)
 	return retval;
 }
 
+S32 LLViewerObject::setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID)
+{
+	S32 retval = 0;
+	const LLTextureEntry *tep = getTE(te);
+	if (!tep)
+	{
+		LL_WARNS("Material") << "No texture entry for te " << (S32)te
+							 << ", object " << mID
+							 << ", material " << pMaterialID
+							 << LL_ENDL;
+	}
+	//else if (pMaterialID != tep->getMaterialID())
+	{
+		LL_DEBUGS("Material") << "Changing texture entry for te " << (S32)te
+							 << ", object " << mID
+							 << ", material " << pMaterialID
+							 << LL_ENDL;
+		retval = LLPrimitive::setTEMaterialID(te, pMaterialID);
+		refreshMaterials();
+	}
+	return retval;
+}
+
+S32 LLViewerObject::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams)
+{
+	S32 retval = 0;
+	const LLTextureEntry *tep = getTE(te);
+	if (!tep)
+	{
+		llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl;
+		return 0;
+	}
+
+	retval = LLPrimitive::setTEMaterialParams(te, pMaterialParams);
+	LL_DEBUGS("Material") << "Changing material params for te " << (S32)te
+							<< ", object " << mID
+			               << " (" << retval << ")"
+							<< LL_ENDL;
+	setTENormalMap(te, (pMaterialParams) ? pMaterialParams->getNormalID() : LLUUID::null);
+	setTESpecularMap(te, (pMaterialParams) ? pMaterialParams->getSpecularID() : LLUUID::null);
+
+	refreshMaterials();
+	return retval;
+}
+
+void LLViewerObject::refreshMaterials()
+{
+	setChanged(ALL_CHANGED);
+	if (mDrawable.notNull())
+	{
+		gPipeline.markTextured(mDrawable);
+		gPipeline.markRebuild(mDrawable,LLDrawable::REBUILD_ALL);
+		dirtySpatialGroup(TRUE);
+	}
+}
 
 S32 LLViewerObject::setTEScale(const U8 te, const F32 s, const F32 t)
 {
@@ -4344,6 +4519,50 @@ LLViewerTexture *LLViewerObject::getTEImage(const U8 face) const
 }
 
 
+LLViewerTexture *LLViewerObject::getTENormalMap(const U8 face) const
+{
+	//	llassert(mTEImages);
+	
+	if (face < getNumTEs())
+	{
+		LLViewerTexture* image = mTENormalMaps[face];
+		if (image)
+		{
+			return image;
+		}
+		else
+		{
+			return (LLViewerTexture*)(LLViewerFetchedTexture::sDefaultImagep);
+		}
+	}
+	
+	llerrs << llformat("Requested Image from invalid face: %d/%d",face,getNumTEs()) << llendl;
+	
+	return NULL;
+}
+
+LLViewerTexture *LLViewerObject::getTESpecularMap(const U8 face) const
+{
+	//	llassert(mTEImages);
+	
+	if (face < getNumTEs())
+	{
+		LLViewerTexture* image = mTESpecularMaps[face];
+		if (image)
+		{
+			return image;
+		}
+		else
+		{
+			return (LLViewerTexture*)(LLViewerFetchedTexture::sDefaultImagep);
+		}
+	}
+	
+	llerrs << llformat("Requested Image from invalid face: %d/%d",face,getNumTEs()) << llendl;
+	
+	return NULL;
+}
+
 void LLViewerObject::fitFaceTexture(const U8 face)
 {
 	llinfos << "fitFaceTexture not implemented" << llendl;
diff --git a/indra/newview/llviewerobject.h b/indra/newview/llviewerobject.h
index 316dbce7d07eca427072af14d06ef39f67c52e55..ea0d55cda53828367bc969fc2912923be61e0a45 100755
--- a/indra/newview/llviewerobject.h
+++ b/indra/newview/llviewerobject.h
@@ -211,7 +211,7 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	LLViewerRegion* getRegion() const				{ return mRegionp; }
 
 	BOOL isSelected() const							{ return mUserSelected; }
-	virtual void setSelected(BOOL sel)				{ mUserSelected = sel; resetRot();}
+	virtual void setSelected(BOOL sel);
 
 	const LLUUID &getID() const						{ return mID; }
 	U32 getLocalID() const							{ return mLocalID; }
@@ -258,17 +258,17 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 
 	//detect if given line segment (in agent space) intersects with this viewer object.
 	//returns TRUE if intersection detected and returns information about intersection
-	virtual BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
+	virtual BOOL lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
 									  S32 face = -1,                          // which face to check, -1 = ALL_SIDES
 									  BOOL pick_transparent = FALSE,
 									  S32* face_hit = NULL,                   // which face was hit
-									  LLVector3* intersection = NULL,         // return the intersection point
+									  LLVector4a* intersection = NULL,         // return the intersection point
 									  LLVector2* tex_coord = NULL,            // return the texture coordinates of the intersection point
-									  LLVector3* normal = NULL,               // return the surface normal at the intersection point
-									  LLVector3* bi_normal = NULL             // return the surface bi-normal at the intersection point
+									  LLVector4a* normal = NULL,               // return the surface normal at the intersection point
+									  LLVector4a* tangent = NULL             // return the surface tangent at the intersection point
 		);
 	
-	virtual BOOL lineSegmentBoundingBox(const LLVector3& start, const LLVector3& end);
+	virtual BOOL lineSegmentBoundingBox(const LLVector4a& start, const LLVector4a& end);
 
 	virtual const LLVector3d getPositionGlobal() const;
 	virtual const LLVector3 &getPositionRegion() const;
@@ -301,7 +301,11 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	/*virtual*/	void	setNumTEs(const U8 num_tes);
 	/*virtual*/	void	setTE(const U8 te, const LLTextureEntry &texture_entry);
 	/*virtual*/ S32		setTETexture(const U8 te, const LLUUID &uuid);
-	S32 				setTETextureCore(const U8 te, LLViewerTexture *image);
+	/*virtual*/ S32		setTENormalMap(const U8 te, const LLUUID &uuid);
+	/*virtual*/ S32		setTESpecularMap(const U8 te, const LLUUID &uuid);
+	S32 setTETextureCore(const U8 te, LLViewerTexture *image);
+	S32 setTENormalMapCore(const U8 te, LLViewerTexture *image);
+	S32 setTESpecularMapCore(const U8 te, LLViewerTexture *image);
 	/*virtual*/ S32		setTEColor(const U8 te, const LLColor3 &color);
 	/*virtual*/ S32		setTEColor(const U8 te, const LLColor4 &color);
 	/*virtual*/ S32		setTEScale(const U8 te, const F32 s, const F32 t);
@@ -318,10 +322,22 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	/*virtual*/	S32		setTEFullbright(const U8 te, const U8 fullbright );
 	/*virtual*/	S32		setTEMediaFlags(const U8 te, const U8 media_flags );
 	/*virtual*/ S32     setTEGlow(const U8 te, const F32 glow);
+	/*virtual*/ S32     setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID);
+	/*virtual*/ S32		setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams);
+
+	// Used by Materials update functions to properly kick off rebuilds
+	// of VBs etc when materials updates require changes.
+	//
+	void refreshMaterials();
+
 	/*virtual*/	BOOL	setMaterial(const U8 material);
 	virtual		void	setTEImage(const U8 te, LLViewerTexture *imagep); // Not derived from LLPrimitive
 	virtual     void    changeTEImage(S32 index, LLViewerTexture* new_image)  ;
+	virtual     void    changeTENormalMap(S32 index, LLViewerTexture* new_image)  ;
+	virtual     void    changeTESpecularMap(S32 index, LLViewerTexture* new_image)  ;
 	LLViewerTexture		*getTEImage(const U8 te) const;
+	LLViewerTexture		*getTENormalMap(const U8 te) const;
+	LLViewerTexture		*getTESpecularMap(const U8 te) const;
 	
 	void fitFaceTexture(const U8 face);
 	void sendTEUpdate() const;			// Sends packed representation of all texture entry information
@@ -596,6 +612,8 @@ class LLViewerObject : public LLPrimitive, public LLRefCount, public LLGLUpdate
 	S32				mListIndex;
 
 	LLPointer<LLViewerTexture> *mTEImages;
+	LLPointer<LLViewerTexture> *mTENormalMaps;
+	LLPointer<LLViewerTexture> *mTESpecularMaps;
 
 	// Selection, picking and rendering variables
 	U32				mGLName;			// GL "name" used by selection code
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 41f63c7ef6536432f82a8f2d642822a2a700cece..e9708fdba0f66a28ff8b8b98fd28b18cbd65255a 100755
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -143,7 +143,7 @@ class LLViewerRegionImpl {
 
 	CapabilityMap mCapabilities;
 	CapabilityMap mSecondCapabilitiesTracker; 
-
+	
 	LLEventPoll* mEventPoll;
 
 	S32 mSeedCapMaxAttempts;
@@ -220,7 +220,7 @@ class BaseCapabilitiesComplete : public LLHTTPClient::Responder
 		}
     }
 
-   void result(const LLSD& content)
+    void result(const LLSD& content)
     {
 		LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(mRegionHandle);
 		if(!regionp) //region was removed
@@ -1587,7 +1587,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
 	capabilityNames.append("EventQueueGet");
 
 	if (gSavedSettings.getBOOL("UseHTTPInventory"))
-	{	
+	{
 		capabilityNames.append("FetchLib2");
 		capabilityNames.append("FetchLibDescendents2");
 		capabilityNames.append("FetchInventory2");
@@ -1607,7 +1607,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
 	capabilityNames.append("LandResources");
 	capabilityNames.append("MapLayer");
 	capabilityNames.append("MapLayerGod");
-	capabilityNames.append("MeshUploadFlag");	
+	capabilityNames.append("MeshUploadFlag");
 	capabilityNames.append("NavMeshGenerationStatus");
 	capabilityNames.append("NewFileAgentInventory");
 	capabilityNames.append("ObjectMedia");
@@ -1618,6 +1618,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
 	capabilityNames.append("ProductInfoRequest");
 	capabilityNames.append("ProvisionVoiceAccountRequest");
 	capabilityNames.append("RemoteParcelRequest");
+	capabilityNames.append("RenderMaterials");
 	capabilityNames.append("RequestTextureDownload");
 	capabilityNames.append("ResourceCostSelected");
 	capabilityNames.append("RetrieveNavMeshSrc");
@@ -1647,7 +1648,7 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
 	capabilityNames.append("ViewerMetrics");
 	capabilityNames.append("ViewerStartAuction");
 	capabilityNames.append("ViewerStats");
-
+	
 	// Please add new capabilities alphabetically to reduce
 	// merge conflicts.
 }
@@ -1655,8 +1656,8 @@ void LLViewerRegionImpl::buildCapabilityNames(LLSD& capabilityNames)
 void LLViewerRegion::setSeedCapability(const std::string& url)
 {
 	if (getCapability("Seed") == url)
-    {	
-		//llwarns << "Ignoring duplicate seed capability" << llendl;
+    {
+		// llwarns << "Ignoring duplicate seed capability" << llendl;
 		//Instead of just returning we build up a second set of seed caps and compare them 
 		//to the "original" seed cap received and determine why there is problem!
 		LLSD capabilityNames = LLSD::emptyArray();
diff --git a/indra/newview/llviewerregion.h b/indra/newview/llviewerregion.h
index b5fe4677b76111471b3d870ad068e5ea88359e67..56cd0c9ea1a204bbb096ce4c12ec01435643eb17 100755
--- a/indra/newview/llviewerregion.h
+++ b/indra/newview/llviewerregion.h
@@ -342,7 +342,7 @@ class LLViewerRegion: public LLCapabilityProvider // implements this interface
 	void getNeighboringRegionsStatus( std::vector<S32>& regions );
 	const LLViewerRegionImpl * getRegionImpl() const { return mImpl; }
 	LLViewerRegionImpl * getRegionImplNC() { return mImpl; }
-
+	
 public:
 	struct CompareDistance
 	{
diff --git a/indra/newview/llviewershadermgr.cpp b/indra/newview/llviewershadermgr.cpp
index ba9818946cbffdfa4157ff75b5932f1d4d261acb..e24237522a1adf4301325a79b56049ec8771a84e 100755
--- a/indra/newview/llviewershadermgr.cpp
+++ b/indra/newview/llviewershadermgr.cpp
@@ -44,6 +44,18 @@
 
 #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
@@ -68,7 +80,7 @@ LLGLSLShader			gTransformPositionProgram;
 LLGLSLShader			gTransformTexCoordProgram;
 LLGLSLShader			gTransformNormalProgram;
 LLGLSLShader			gTransformColorProgram;
-LLGLSLShader			gTransformBinormalProgram;
+LLGLSLShader			gTransformTangentProgram;
 
 //utility shaders
 LLGLSLShader	gOcclusionProgram;
@@ -81,6 +93,8 @@ LLGLSLShader	gTwoTextureAddProgram;
 LLGLSLShader	gOneTextureNoColorProgram;
 LLGLSLShader	gDebugProgram;
 LLGLSLShader	gClipProgram;
+LLGLSLShader	gDownsampleDepthProgram;
+LLGLSLShader	gDownsampleDepthRectProgram;
 LLGLSLShader	gAlphaMaskProgram;
 
 //object shaders
@@ -143,6 +157,9 @@ LLGLSLShader		gUnderWaterProgram;
 
 //interface shaders
 LLGLSLShader		gHighlightProgram;
+LLGLSLShader		gHighlightNormalProgram;
+LLGLSLShader		gHighlightSpecularProgram;
+
 LLGLSLShader		gPathfindingProgram;
 LLGLSLShader		gPathfindingNoNormalsProgram;
 
@@ -200,13 +217,20 @@ LLGLSLShader			gDeferredEmissiveProgram;
 LLGLSLShader			gDeferredPostProgram;
 LLGLSLShader			gDeferredCoFProgram;
 LLGLSLShader			gDeferredDoFCombineProgram;
+LLGLSLShader			gDeferredPostGammaCorrectProgram;
 LLGLSLShader			gFXAAProgram;
 LLGLSLShader			gDeferredPostNoDoFProgram;
 LLGLSLShader			gDeferredWLSkyProgram;
 LLGLSLShader			gDeferredWLCloudProgram;
 LLGLSLShader			gDeferredStarProgram;
+LLGLSLShader			gDeferredFullbrightShinyProgram;
+LLGLSLShader			gDeferredSkinnedFullbrightShinyProgram;
+LLGLSLShader			gDeferredSkinnedFullbrightProgram;
 LLGLSLShader			gNormalMapGenProgram;
 
+// Deferred materials shaders
+LLGLSLShader			gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2];
+
 LLViewerShaderMgr::LLViewerShaderMgr() :
 	mVertexShaderLevel(SHADER_COUNT, 0),
 	mMaxAvatarShaderLevel(0)
@@ -271,9 +295,20 @@ LLViewerShaderMgr::LLViewerShaderMgr() :
 	mShaderList.push_back(&gUnderWaterProgram);
 	mShaderList.push_back(&gDeferredSunProgram);
 	mShaderList.push_back(&gDeferredSoftenProgram);
+	mShaderList.push_back(&gDeferredMaterialProgram[1]);
+	mShaderList.push_back(&gDeferredMaterialProgram[5]);
+	mShaderList.push_back(&gDeferredMaterialProgram[9]);
+	mShaderList.push_back(&gDeferredMaterialProgram[13]);
+	mShaderList.push_back(&gDeferredMaterialProgram[1+LLMaterial::SHADER_COUNT]);
+	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(&gDeferredAlphaProgram);
 	mShaderList.push_back(&gDeferredSkinnedAlphaProgram);
 	mShaderList.push_back(&gDeferredFullbrightProgram);
+	mShaderList.push_back(&gDeferredFullbrightShinyProgram);
+	mShaderList.push_back(&gDeferredSkinnedFullbrightShinyProgram);
+	mShaderList.push_back(&gDeferredSkinnedFullbrightProgram);
 	mShaderList.push_back(&gDeferredEmissiveProgram);
 	mShaderList.push_back(&gDeferredAvatarEyesProgram);
 	mShaderList.push_back(&gDeferredWaterProgram);
@@ -451,6 +486,12 @@ void LLViewerShaderMgr::setShaders()
 		S32 deferred_class = 0;
 		S32 transform_class = gGLManager.mHasTransformFeedback ? 1 : 0;
 
+		static LLCachedControl<bool> use_transform_feedback(gSavedSettings, "RenderUseTransformFeedback");
+		if (!use_transform_feedback)
+		{
+			transform_class = 0;
+		}
+		
 		if (LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
 		    gSavedSettings.getBOOL("RenderDeferred") &&
 			gSavedSettings.getBOOL("RenderAvatarVP") &&
@@ -663,6 +704,8 @@ void LLViewerShaderMgr::unloadShaders()
 	gOcclusionCubeProgram.unload();
 	gDebugProgram.unload();
 	gClipProgram.unload();
+	gDownsampleDepthProgram.unload();
+	gDownsampleDepthRectProgram.unload();
 	gAlphaMaskProgram.unload();
 	gUIProgram.unload();
 	gPathfindingProgram.unload();
@@ -740,6 +783,8 @@ void LLViewerShaderMgr::unloadShaders()
 	gAvatarEyeballProgram.unload();
 	gAvatarPickProgram.unload();
 	gHighlightProgram.unload();
+	gHighlightNormalProgram.unload();
+	gHighlightSpecularProgram.unload();
 
 	gWLSkyProgram.unload();
 	gWLCloudProgram.unload();
@@ -760,7 +805,7 @@ void LLViewerShaderMgr::unloadShaders()
 	gTransformTexCoordProgram.unload();
 	gTransformNormalProgram.unload();
 	gTransformColorProgram.unload();
-	gTransformBinormalProgram.unload();
+	gTransformTangentProgram.unload();
 
 	mVertexShaderLevel[SHADER_LIGHTING] = 0;
 	mVertexShaderLevel[SHADER_OBJECT] = 0;
@@ -780,9 +825,6 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
 	// Load basic dependency shaders first
 	// All of these have to load for any shaders to function
 	
-#if LL_DARWIN // Mac can't currently handle all 8 lights, 
-	S32 sum_lights_class = 2;
-#else 
 	S32 sum_lights_class = 3;
 
 	// class one cards will get the lower sum lights
@@ -793,7 +835,6 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
 	{
 		sum_lights_class = 2;
 	}
-#endif
 
 	// If we have sun and moon only checked, then only sum those lights.
 	if (gPipeline.getLightingDetail() == 0)
@@ -801,6 +842,14 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
 		sum_lights_class = 1;
 	}
 
+#if LL_DARWIN
+	// Work around driver crashes on older Macs when using deferred rendering
+	// NORSPEC-59
+	//
+	if (gGLManager.mIsMobileGF)
+		sum_lights_class = 3;
+#endif
+	
 	// Use the feature table to mask out the max light level to use.  Also make sure it's at least 1.
 	S32 max_light_class = gSavedSettings.getS32("RenderShaderLightingMaxLevel");
 	sum_lights_class = llclamp(sum_lights_class, 1, max_light_class);
@@ -826,12 +875,14 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
 		shaders.push_back( make_pair( "objects/indexedTextureV.glsl",			1 ) );
 	}
 	shaders.push_back( make_pair( "objects/nonindexedTextureV.glsl",		1 ) );
-
+	
+	boost::unordered_map<std::string, std::string> attribs;
+	
 	// We no longer have to bind the shaders to global glhandles, they are automatically added to a map now.
 	for (U32 i = 0; i < shaders.size(); i++)
 	{
 		// Note usage of GL_VERTEX_SHADER_ARB
-		if (loadShaderFile(shaders[i].first, shaders[i].second, GL_VERTEX_SHADER_ARB) == 0)
+		if (loadShaderFile(shaders[i].first, shaders[i].second, GL_VERTEX_SHADER_ARB, &attribs) == 0)
 		{
 			return FALSE;
 		}
@@ -879,11 +930,11 @@ BOOL LLViewerShaderMgr::loadBasicShaders()
 	index_channels.push_back(ch);	 shaders.push_back( make_pair( "lighting/lightFullbrightShinyF.glsl",	mVertexShaderLevel[SHADER_LIGHTING] ) );
 	index_channels.push_back(ch);	 shaders.push_back( make_pair( "lighting/lightShinyWaterF.glsl",			mVertexShaderLevel[SHADER_LIGHTING] ) );
 	index_channels.push_back(ch);	 shaders.push_back( make_pair( "lighting/lightFullbrightShinyWaterF.glsl", mVertexShaderLevel[SHADER_LIGHTING] ) );
-	
+
 	for (U32 i = 0; i < shaders.size(); i++)
 	{
 		// Note usage of GL_FRAGMENT_SHADER_ARB
-		if (loadShaderFile(shaders[i].first, shaders[i].second, GL_FRAGMENT_SHADER_ARB, index_channels[i]) == 0)
+		if (loadShaderFile(shaders[i].first, shaders[i].second, GL_FRAGMENT_SHADER_ARB, &attribs, index_channels[i]) == 0)
 		{
 			return FALSE;
 		}
@@ -1097,12 +1148,21 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredPostProgram.unload();		
 		gDeferredCoFProgram.unload();		
 		gDeferredDoFCombineProgram.unload();
+		gDeferredPostGammaCorrectProgram.unload();
 		gFXAAProgram.unload();
 		gDeferredWaterProgram.unload();
 		gDeferredWLSkyProgram.unload();
 		gDeferredWLCloudProgram.unload();
 		gDeferredStarProgram.unload();
+		gDeferredFullbrightShinyProgram.unload();
+		gDeferredSkinnedFullbrightShinyProgram.unload();
+		gDeferredSkinnedFullbrightProgram.unload();
+
 		gNormalMapGenProgram.unload();
+		for (U32 i = 0; i < LLMaterial::SHADER_COUNT*2; ++i)
+		{
+			gDeferredMaterialProgram[i].unload();
+		}
 		return TRUE;
 	}
 
@@ -1196,10 +1256,13 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredSkinnedAlphaProgram.mFeatures.isAlphaLighting = true;
 		gDeferredSkinnedAlphaProgram.mFeatures.disableTextureIndex = true;
 		gDeferredSkinnedAlphaProgram.mShaderFiles.clear();
-		gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaNonIndexedF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredSkinnedAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
+		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("HAS_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0");
 		success = gDeferredSkinnedAlphaProgram.createShader(NULL, NULL);
 		
 		// Hack to include uniforms for lighting without linking in lighting file
@@ -1216,7 +1279,57 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredBumpProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredBumpProgram.createShader(NULL, NULL);
 	}
+	
+	gDeferredMaterialProgram[1].mFeatures.hasLighting = false;
+	gDeferredMaterialProgram[5].mFeatures.hasLighting = false;
+	gDeferredMaterialProgram[9].mFeatures.hasLighting = false;
+	gDeferredMaterialProgram[13].mFeatures.hasLighting = false;
+	gDeferredMaterialProgram[1+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
+	gDeferredMaterialProgram[5+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
+	gDeferredMaterialProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
+	gDeferredMaterialProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = false;
 
+	for (U32 i = 0; i < LLMaterial::SHADER_COUNT*2; ++i)
+	{
+		if (success)
+		{
+			gDeferredMaterialProgram[i].mName = llformat("Deferred Material Shader %d", i);
+			
+			U32 alpha_mode = i & 0x3;
+
+			gDeferredMaterialProgram[i].mShaderFiles.clear();
+			gDeferredMaterialProgram[i].mShaderFiles.push_back(make_pair("deferred/materialV.glsl", GL_VERTEX_SHADER_ARB));
+			gDeferredMaterialProgram[i].mShaderFiles.push_back(make_pair("deferred/materialF.glsl", GL_FRAGMENT_SHADER_ARB));
+			gDeferredMaterialProgram[i].mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+			gDeferredMaterialProgram[i].addPermutation("HAS_NORMAL_MAP", i & 0x8? "1" : "0");
+			gDeferredMaterialProgram[i].addPermutation("HAS_SPECULAR_MAP", i & 0x4 ? "1" : "0");
+			gDeferredMaterialProgram[i].addPermutation("DIFFUSE_ALPHA_MODE", llformat("%d", alpha_mode));
+			gDeferredMaterialProgram[i].addPermutation("HAS_SUN_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0");
+			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;
+			}
+
+			success = gDeferredMaterialProgram[i].createShader(NULL, NULL);
+		}
+	}
+
+	gDeferredMaterialProgram[1].mFeatures.hasLighting = true;
+	gDeferredMaterialProgram[5].mFeatures.hasLighting = true;
+	gDeferredMaterialProgram[9].mFeatures.hasLighting = true;
+	gDeferredMaterialProgram[13].mFeatures.hasLighting = true;
+	gDeferredMaterialProgram[1+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
+	gDeferredMaterialProgram[5+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
+	gDeferredMaterialProgram[9+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
+	gDeferredMaterialProgram[13+LLMaterial::SHADER_COUNT].mFeatures.hasLighting = true;
+
+
+	
 	if (success)
 	{
 		gDeferredTreeProgram.mName = "Deferred Tree Shader";
@@ -1254,6 +1367,9 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB));
 		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);
 	}
 
@@ -1264,6 +1380,9 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		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);
 	}
 
@@ -1274,6 +1393,9 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/pointLightV.glsl", GL_VERTEX_SHADER_ARB));
 		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);
 	}
 
@@ -1284,6 +1406,9 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredMultiSpotLightProgram.mShaderFiles.push_back(make_pair("deferred/multiPointLightV.glsl", GL_VERTEX_SHADER_ARB));
 		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);
 	}
 
@@ -1310,6 +1435,9 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredSunProgram.mShaderFiles.push_back(make_pair(vertex, GL_VERTEX_SHADER_ARB));
 		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);
 	}
 
@@ -1320,6 +1448,9 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredBlurLightProgram.mShaderFiles.push_back(make_pair("deferred/blurLightV.glsl", GL_VERTEX_SHADER_ARB));
 		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);
 	}
 
@@ -1346,8 +1477,13 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAlphaProgram.mShaderFiles.clear();
 		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.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 
+		SINGLE_FP_PERMUTATION(gDeferredAlphaProgram);
+
 		success = gDeferredAlphaProgram.createShader(NULL, NULL);
 
 		// Hack
@@ -1383,6 +1519,50 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		success = gDeferredFullbrightProgram.createShader(NULL, NULL);
 	}
 
+	if (success)
+	{
+		gDeferredFullbrightShinyProgram.mName = "Deferred FullbrightShiny Shader";
+		gDeferredFullbrightShinyProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredFullbrightShinyProgram.mFeatures.hasGamma = true;
+		gDeferredFullbrightShinyProgram.mFeatures.hasTransport = true;
+		gDeferredFullbrightShinyProgram.mFeatures.mIndexedTextureChannels = LLGLSLShader::sIndexedTextureChannels-1;
+		gDeferredFullbrightShinyProgram.mShaderFiles.clear();
+		gDeferredFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredFullbrightShinyProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredFullbrightShinyProgram.createShader(NULL, &mShinyUniforms);
+	}
+
+	if (success)
+	{
+		gDeferredSkinnedFullbrightProgram.mName = "Skinned Fullbright Shader";
+		gDeferredSkinnedFullbrightProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredSkinnedFullbrightProgram.mFeatures.hasGamma = true;
+		gDeferredSkinnedFullbrightProgram.mFeatures.hasTransport = true;
+		gDeferredSkinnedFullbrightProgram.mFeatures.hasObjectSkinning = true;
+		gDeferredSkinnedFullbrightProgram.mFeatures.disableTextureIndex = true;
+		gDeferredSkinnedFullbrightProgram.mShaderFiles.clear();
+		gDeferredSkinnedFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredSkinnedFullbrightProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredSkinnedFullbrightProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		success = gDeferredSkinnedFullbrightProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDeferredSkinnedFullbrightShinyProgram.mName = "Skinned Fullbright Shiny Shader";
+		gDeferredSkinnedFullbrightShinyProgram.mFeatures.calculatesAtmospherics = true;
+		gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasGamma = true;
+		gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasTransport = true;
+		gDeferredSkinnedFullbrightShinyProgram.mFeatures.hasObjectSkinning = true;
+		gDeferredSkinnedFullbrightShinyProgram.mFeatures.disableTextureIndex = true;
+		gDeferredSkinnedFullbrightShinyProgram.mShaderFiles.clear();
+		gDeferredSkinnedFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredSkinnedFullbrightShinyProgram.mShaderFiles.push_back(make_pair("deferred/fullbrightShinyF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredSkinnedFullbrightShinyProgram.mShaderLevel = mVertexShaderLevel[SHADER_OBJECT];
+		success = gDeferredSkinnedFullbrightShinyProgram.createShader(NULL, &mShinyUniforms);
+	}
+
 	if (success)
 	{
 		gDeferredEmissiveProgram.mName = "Deferred Emissive Shader";
@@ -1420,6 +1600,8 @@ 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);
@@ -1435,6 +1617,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredShadowProgram.mShaderFiles.push_back(make_pair("deferred/shadowV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredShadowProgram.mShaderFiles.push_back(make_pair("deferred/shadowF.glsl", GL_FRAGMENT_SHADER_ARB));
 		gDeferredShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		gDeferredShadowProgram.addPermutation("DEPTH_CLAMP", gGLManager.mHasDepthClamp ? "1" : "0");
 		success = gDeferredShadowProgram.createShader(NULL, NULL);
 	}
 
@@ -1444,6 +1627,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredShadowCubeProgram.mShaderFiles.clear();
 		gDeferredShadowCubeProgram.mShaderFiles.push_back(make_pair("deferred/shadowCubeV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredShadowCubeProgram.mShaderFiles.push_back(make_pair("deferred/shadowF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredShadowCubeProgram.addPermutation("DEPTH_CLAMP", gGLManager.mHasDepthClamp ? "1" : "0");
 		gDeferredShadowCubeProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredShadowCubeProgram.createShader(NULL, NULL);
 	}
@@ -1455,6 +1639,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredShadowAlphaMaskProgram.mShaderFiles.clear();
 		gDeferredShadowAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredShadowAlphaMaskProgram.mShaderFiles.push_back(make_pair("deferred/shadowAlphaMaskF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredShadowAlphaMaskProgram.addPermutation("DEPTH_CLAMP", gGLManager.mHasDepthClamp ? "1" : "0");
 		gDeferredShadowAlphaMaskProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredShadowAlphaMaskProgram.createShader(NULL, NULL);
 	}
@@ -1466,6 +1651,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAvatarShadowProgram.mShaderFiles.clear();
 		gDeferredAvatarShadowProgram.mShaderFiles.push_back(make_pair("deferred/avatarShadowV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredAvatarShadowProgram.mShaderFiles.push_back(make_pair("deferred/avatarShadowF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredAvatarShadowProgram.addPermutation("DEPTH_CLAMP", gGLManager.mHasDepthClamp ? "1" : "0");
 		gDeferredAvatarShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredAvatarShadowProgram.createShader(NULL, &mAvatarUniforms);
 	}
@@ -1477,6 +1663,7 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAttachmentShadowProgram.mShaderFiles.clear();
 		gDeferredAttachmentShadowProgram.mShaderFiles.push_back(make_pair("deferred/attachmentShadowV.glsl", GL_VERTEX_SHADER_ARB));
 		gDeferredAttachmentShadowProgram.mShaderFiles.push_back(make_pair("deferred/attachmentShadowF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredAttachmentShadowProgram.addPermutation("DEPTH_CLAMP", gGLManager.mHasDepthClamp ? "1" : "0");
 		gDeferredAttachmentShadowProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 		success = gDeferredAttachmentShadowProgram.createShader(NULL, NULL);
 	}
@@ -1515,8 +1702,11 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAvatarAlphaProgram.mFeatures.isAlphaLighting = true;
 		gDeferredAvatarAlphaProgram.mFeatures.disableTextureIndex = true;
 		gDeferredAvatarAlphaProgram.mShaderFiles.clear();
-		gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/avatarAlphaNoColorV.glsl", GL_VERTEX_SHADER_ARB));
-		gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaNonIndexedNoColorF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredAvatarAlphaProgram.mShaderFiles.push_back(make_pair("deferred/alphaF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredAvatarAlphaProgram.addPermutation("USE_DIFFUSE_TEX", "1");
+		gDeferredAvatarAlphaProgram.addPermutation("IS_AVATAR_SKIN", "1");
+		gDeferredAvatarAlphaProgram.addPermutation("HAS_SHADOW", mVertexShaderLevel[SHADER_DEFERRED] > 1 ? "1" : "0");
 		gDeferredAvatarAlphaProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
 
 		success = gDeferredAvatarAlphaProgram.createShader(NULL, &mAvatarUniforms);
@@ -1524,6 +1714,16 @@ BOOL LLViewerShaderMgr::loadShadersDeferred()
 		gDeferredAvatarAlphaProgram.mFeatures.calculatesLighting = true;
 		gDeferredAvatarAlphaProgram.mFeatures.hasLighting = true;
 	}
+	
+	if (success)
+	{
+		gDeferredPostGammaCorrectProgram.mName = "Deferred Gamma Correction Post Process";
+		gDeferredPostGammaCorrectProgram.mShaderFiles.clear();
+		gDeferredPostGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredNoTCV.glsl", GL_VERTEX_SHADER_ARB));
+		gDeferredPostGammaCorrectProgram.mShaderFiles.push_back(make_pair("deferred/postDeferredGammaCorrect.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDeferredPostGammaCorrectProgram.mShaderLevel = mVertexShaderLevel[SHADER_DEFERRED];
+		success = gDeferredPostGammaCorrectProgram.createShader(NULL, NULL);
+	}
 
 	if (success)
 	{
@@ -2306,6 +2506,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 			gSkinnedObjectSimpleProgram.mFeatures.hasAtmospherics = true;
 			gSkinnedObjectSimpleProgram.mFeatures.hasLighting = true;
 			gSkinnedObjectSimpleProgram.mFeatures.hasObjectSkinning = true;
+			gSkinnedObjectSimpleProgram.mFeatures.hasAlphaMask = true;
 			gSkinnedObjectSimpleProgram.mFeatures.disableTextureIndex = true;
 			gSkinnedObjectSimpleProgram.mShaderFiles.clear();
 			gSkinnedObjectSimpleProgram.mShaderFiles.push_back(make_pair("objects/simpleSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
@@ -2322,6 +2523,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 			gSkinnedObjectFullbrightProgram.mFeatures.hasTransport = true;
 			gSkinnedObjectFullbrightProgram.mFeatures.isFullbright = true;
 			gSkinnedObjectFullbrightProgram.mFeatures.hasObjectSkinning = true;
+			gSkinnedObjectFullbrightProgram.mFeatures.hasAlphaMask = true;			
 			gSkinnedObjectFullbrightProgram.mFeatures.disableTextureIndex = true;
 			gSkinnedObjectFullbrightProgram.mShaderFiles.clear();
 			gSkinnedObjectFullbrightProgram.mShaderFiles.push_back(make_pair("objects/fullbrightSkinnedV.glsl", GL_VERTEX_SHADER_ARB));
@@ -2372,6 +2574,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 			gSkinnedObjectFullbrightShinyProgram.mFeatures.isShiny = true;
 			gSkinnedObjectFullbrightShinyProgram.mFeatures.isFullbright = true;
 			gSkinnedObjectFullbrightShinyProgram.mFeatures.hasObjectSkinning = true;
+			gSkinnedObjectFullbrightShinyProgram.mFeatures.hasAlphaMask = true;
 			gSkinnedObjectFullbrightShinyProgram.mFeatures.disableTextureIndex = true;
 			gSkinnedObjectFullbrightShinyProgram.mShaderFiles.clear();
 			gSkinnedObjectFullbrightShinyProgram.mShaderFiles.push_back(make_pair("objects/fullbrightShinySkinnedV.glsl", GL_VERTEX_SHADER_ARB));
@@ -2388,6 +2591,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 			gSkinnedObjectShinySimpleProgram.mFeatures.hasGamma = true;
 			gSkinnedObjectShinySimpleProgram.mFeatures.hasAtmospherics = true;
 			gSkinnedObjectShinySimpleProgram.mFeatures.hasObjectSkinning = true;
+			gSkinnedObjectShinySimpleProgram.mFeatures.hasAlphaMask = true;
 			gSkinnedObjectShinySimpleProgram.mFeatures.isShiny = true;
 			gSkinnedObjectShinySimpleProgram.mFeatures.disableTextureIndex = true;
 			gSkinnedObjectShinySimpleProgram.mShaderFiles.clear();
@@ -2425,6 +2629,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 			gSkinnedObjectFullbrightWaterProgram.mFeatures.hasTransport = true;
 			gSkinnedObjectFullbrightWaterProgram.mFeatures.isFullbright = true;
 			gSkinnedObjectFullbrightWaterProgram.mFeatures.hasObjectSkinning = true;
+			gSkinnedObjectFullbrightWaterProgram.mFeatures.hasAlphaMask = true;
 			gSkinnedObjectFullbrightWaterProgram.mFeatures.hasWaterFog = true;
 			gSkinnedObjectFullbrightWaterProgram.mFeatures.disableTextureIndex = true;
 			gSkinnedObjectFullbrightWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
@@ -2444,6 +2649,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.isShiny = true;
 			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.isFullbright = true;
 			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasObjectSkinning = true;
+			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasAlphaMask = true;
 			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.hasWaterFog = true;
 			gSkinnedObjectFullbrightShinyWaterProgram.mFeatures.disableTextureIndex = true;
 			gSkinnedObjectFullbrightShinyWaterProgram.mShaderGroup = LLGLSLShader::SG_WATER;
@@ -2462,6 +2668,7 @@ BOOL LLViewerShaderMgr::loadShadersObject()
 			gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasGamma = true;
 			gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasAtmospherics = true;
 			gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasObjectSkinning = true;
+			gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasAlphaMask = true;
 			gSkinnedObjectShinySimpleWaterProgram.mFeatures.isShiny = true;
 			gSkinnedObjectShinySimpleWaterProgram.mFeatures.hasWaterFog = true;
 			gSkinnedObjectShinySimpleWaterProgram.mFeatures.disableTextureIndex = true;
@@ -2600,6 +2807,26 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
 		success = gHighlightProgram.createShader(NULL, NULL);
 	}
 
+	if (success)
+	{
+		gHighlightNormalProgram.mName = "Highlight Normals Shader";
+		gHighlightNormalProgram.mShaderFiles.clear();
+		gHighlightNormalProgram.mShaderFiles.push_back(make_pair("interface/highlightNormV.glsl", GL_VERTEX_SHADER_ARB));
+		gHighlightNormalProgram.mShaderFiles.push_back(make_pair("interface/highlightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gHighlightNormalProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE];		
+		success = gHighlightNormalProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gHighlightSpecularProgram.mName = "Highlight Spec Shader";
+		gHighlightSpecularProgram.mShaderFiles.clear();
+		gHighlightSpecularProgram.mShaderFiles.push_back(make_pair("interface/highlightSpecV.glsl", GL_VERTEX_SHADER_ARB));
+		gHighlightSpecularProgram.mShaderFiles.push_back(make_pair("interface/highlightF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gHighlightSpecularProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE];		
+		success = gHighlightSpecularProgram.createShader(NULL, NULL);
+	}
+
 	if (success)
 	{
 		gUIProgram.mName = "UI Shader";
@@ -2778,6 +3005,26 @@ BOOL LLViewerShaderMgr::loadShadersInterface()
 		success = gClipProgram.createShader(NULL, NULL);
 	}
 
+	if (success)
+	{
+		gDownsampleDepthProgram.mName = "DownsampleDepth Shader";
+		gDownsampleDepthProgram.mShaderFiles.clear();
+		gDownsampleDepthProgram.mShaderFiles.push_back(make_pair("interface/downsampleDepthV.glsl", GL_VERTEX_SHADER_ARB));
+		gDownsampleDepthProgram.mShaderFiles.push_back(make_pair("interface/downsampleDepthF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDownsampleDepthProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE];
+		success = gDownsampleDepthProgram.createShader(NULL, NULL);
+	}
+
+	if (success)
+	{
+		gDownsampleDepthRectProgram.mName = "DownsampleDepthRect Shader";
+		gDownsampleDepthRectProgram.mShaderFiles.clear();
+		gDownsampleDepthRectProgram.mShaderFiles.push_back(make_pair("interface/downsampleDepthV.glsl", GL_VERTEX_SHADER_ARB));
+		gDownsampleDepthRectProgram.mShaderFiles.push_back(make_pair("interface/downsampleDepthRectF.glsl", GL_FRAGMENT_SHADER_ARB));
+		gDownsampleDepthRectProgram.mShaderLevel = mVertexShaderLevel[SHADER_INTERFACE];
+		success = gDownsampleDepthRectProgram.createShader(NULL, NULL);
+	}
+
 	if (success)
 	{
 		gAlphaMaskProgram.mName = "Alpha Mask Shader";
@@ -2845,7 +3092,7 @@ BOOL LLViewerShaderMgr::loadTransformShaders()
 		gTransformTexCoordProgram.unload();
 		gTransformNormalProgram.unload();
 		gTransformColorProgram.unload();
-		gTransformBinormalProgram.unload();
+		gTransformTangentProgram.unload();
 		return TRUE;
 	}
 
@@ -2908,16 +3155,16 @@ BOOL LLViewerShaderMgr::loadTransformShaders()
 
 	if (success)
 	{
-		gTransformBinormalProgram.mName = "Binormal Transform Shader";
-		gTransformBinormalProgram.mShaderFiles.clear();
-		gTransformBinormalProgram.mShaderFiles.push_back(make_pair("transform/binormalV.glsl", GL_VERTEX_SHADER_ARB));
-		gTransformBinormalProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM];
+		gTransformTangentProgram.mName = "Binormal Transform Shader";
+		gTransformTangentProgram.mShaderFiles.clear();
+		gTransformTangentProgram.mShaderFiles.push_back(make_pair("transform/binormalV.glsl", GL_VERTEX_SHADER_ARB));
+		gTransformTangentProgram.mShaderLevel = mVertexShaderLevel[SHADER_TRANSFORM];
 
 		const char* varyings[] = {
-			"binormal_out",
+			"tangent_out",
 		};
 	
-		success = gTransformBinormalProgram.createShader(NULL, NULL, 1, varyings);
+		success = gTransformTangentProgram.createShader(NULL, NULL, 1, varyings);
 	}
 
 	
diff --git a/indra/newview/llviewershadermgr.h b/indra/newview/llviewershadermgr.h
index e3d28f2f5c21f42d51f641274e62d211e96a624d..438853cd6f7ef46117c5014842945789958e924e 100755
--- a/indra/newview/llviewershadermgr.h
+++ b/indra/newview/llviewershadermgr.h
@@ -28,6 +28,7 @@
 #define LL_VIEWER_SHADER_MGR_H
 
 #include "llshadermgr.h"
+#include "llmaterial.h"
 
 class LLViewerShaderMgr: public LLShaderMgr
 {
@@ -216,7 +217,7 @@ extern LLGLSLShader			gTransformPositionProgram;
 extern LLGLSLShader			gTransformTexCoordProgram;
 extern LLGLSLShader			gTransformNormalProgram;
 extern LLGLSLShader			gTransformColorProgram;
-extern LLGLSLShader			gTransformBinormalProgram;
+extern LLGLSLShader			gTransformTangentProgram;
 
 
 
@@ -229,6 +230,8 @@ extern LLGLSLShader			gSplatTextureRectProgram;
 extern LLGLSLShader			gGlowCombineFXAAProgram;
 extern LLGLSLShader			gDebugProgram;
 extern LLGLSLShader			gClipProgram;
+extern LLGLSLShader			gDownsampleDepthProgram;
+extern LLGLSLShader			gDownsampleDepthRectProgram;
 
 //output tex0[tc0] + tex1[tc1]
 extern LLGLSLShader			gTwoTextureAddProgram;
@@ -300,6 +303,9 @@ extern LLGLSLShader			gGlowExtractProgram;
 
 //interface shaders
 extern LLGLSLShader			gHighlightProgram;
+extern LLGLSLShader			gHighlightNormalProgram;
+extern LLGLSLShader			gHighlightSpecularProgram;
+
 extern LLGLSLShader			gPathfindingProgram;
 extern LLGLSLShader			gPathfindingNoNormalsProgram;
 
@@ -318,6 +324,7 @@ extern LLGLSLShader			gWLCloudProgram;
 extern LLGLSLShader			gPostColorFilterProgram;
 extern LLGLSLShader			gPostNightVisionProgram;
 
+
 // Deferred rendering shaders
 extern LLGLSLShader			gDeferredImpostorProgram;
 extern LLGLSLShader			gDeferredWaterProgram;
@@ -349,6 +356,7 @@ extern LLGLSLShader			gDeferredCoFProgram;
 extern LLGLSLShader			gDeferredDoFCombineProgram;
 extern LLGLSLShader			gFXAAProgram;
 extern LLGLSLShader			gDeferredPostNoDoFProgram;
+extern LLGLSLShader			gDeferredPostGammaCorrectProgram;
 extern LLGLSLShader			gDeferredAvatarShadowProgram;
 extern LLGLSLShader			gDeferredAttachmentShadowProgram;
 extern LLGLSLShader			gDeferredAlphaProgram;
@@ -359,6 +367,12 @@ extern LLGLSLShader			gDeferredAvatarAlphaProgram;
 extern LLGLSLShader			gDeferredWLSkyProgram;
 extern LLGLSLShader			gDeferredWLCloudProgram;
 extern LLGLSLShader			gDeferredStarProgram;
+extern LLGLSLShader			gDeferredFullbrightShinyProgram;
+extern LLGLSLShader			gDeferredSkinnedFullbrightShinyProgram;
+extern LLGLSLShader			gDeferredSkinnedFullbrightProgram;
 extern LLGLSLShader			gNormalMapGenProgram;
 
+// Deferred materials shaders
+extern LLGLSLShader			gDeferredMaterialProgram[LLMaterial::SHADER_COUNT*2];
+
 #endif
diff --git a/indra/newview/llviewerstatsrecorder.cpp b/indra/newview/llviewerstatsrecorder.cpp
index f9a725547f6faa0c8f425b2757fc983973111101..2b3e2932292f3b298fc54b37424e8566e9457e08 100755
--- a/indra/newview/llviewerstatsrecorder.cpp
+++ b/indra/newview/llviewerstatsrecorder.cpp
@@ -166,6 +166,7 @@ void LLViewerStatsRecorder::recordRequestCacheMissesEvent(S32 count)
 
 void LLViewerStatsRecorder::writeToLog( F32 interval )
 {
+	size_t data_size = 0;
 	F64 delta_time = LLTimer::getTotalSeconds() - mLastSnapshotTime;
 	S32 total_objects = mObjectCacheHitCount + mObjectCacheMissCrcCount + mObjectCacheMissFullCount + mObjectFullUpdates + mObjectTerseUpdates + mObjectCacheMissRequests + mObjectCacheMissResponses + mObjectCacheUpdateDupes + mObjectCacheUpdateChanges + mObjectCacheUpdateAdds + mObjectCacheUpdateReplacements + mObjectUpdateFailures;
 
@@ -187,7 +188,6 @@ void LLViewerStatsRecorder::writeToLog( F32 interval )
 		<< mObjectUpdateFailures << " update failures"
 		<< llendl;
 
-	U32 data_size;
 	if (mObjectCacheFile == NULL)
 	{
 		mStartTime = LLTimer::getTotalSeconds();
@@ -255,9 +255,9 @@ void LLViewerStatsRecorder::writeToLog( F32 interval )
 		<< "\n";
 
 	data_size = data_msg.str().size();
-	if (fwrite(data_msg.str().c_str(), 1, data_size, mObjectCacheFile ) != data_size)
+	if ( data_size != fwrite(data_msg.str().c_str(), 1, data_size, mObjectCacheFile ))
 	{
-		llwarns << "failed to write full stats to " << STATS_FILE_NAME << llendl;
+				llwarns << "Unable to write complete column data to " << STATS_FILE_NAME << llendl;
 	}
 
 	clearStats();
diff --git a/indra/newview/llviewertexture.cpp b/indra/newview/llviewertexture.cpp
index eb6c453e765d74bbcc984d12006fc5587be1aa10..6cc9f4ace178506abade0d17529b7892ab57b493 100755
--- a/indra/newview/llviewertexture.cpp
+++ b/indra/newview/llviewertexture.cpp
@@ -55,8 +55,6 @@
 #include "llappviewer.h"
 #include "llface.h"
 #include "llviewercamera.h"
-#include "lltextureatlas.h"
-#include "lltextureatlasmanager.h"
 #include "lltextureentry.h"
 #include "lltexturemanagerbridge.h"
 #include "llmediaentry.h"
@@ -73,6 +71,7 @@ LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sMissingAssetImagep =
 LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sWhiteImagep = NULL;
 LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sDefaultImagep = NULL;
 LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sSmokeImagep = NULL;
+LLPointer<LLViewerFetchedTexture> LLViewerFetchedTexture::sFlatNormalImagep = NULL;
 LLViewerMediaTexture::media_map_t LLViewerMediaTexture::sMediaMap ;
 LLTexturePipelineTester* LLViewerTextureManager::sTesterp = NULL ;
 const std::string sTesterName("TextureTester");
@@ -98,7 +97,6 @@ S32 LLViewerTexture::sMinLargeImageSize = 65536 ; //256 * 256.
 S32 LLViewerTexture::sMaxSmallImageSize = MAX_CACHED_RAW_IMAGE_AREA ;
 BOOL LLViewerTexture::sFreezeImageScalingDown = FALSE ;
 F32 LLViewerTexture::sCurrentTime = 0.0f ;
-BOOL LLViewerTexture::sUseTextureAtlas        = FALSE ;
 F32  LLViewerTexture::sTexelPixelRatio = 1.0f;
 
 LLViewerTexture::EDebugTexels LLViewerTexture::sDebugTexelsMode = LLViewerTexture::DEBUG_TEXELS_OFF;
@@ -277,7 +275,7 @@ LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTexture(
 }
 	
 LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromFile(
-	                                               const std::string& filename,
+	                                               const std::string& filename,												   
 												   FTType f_type,
 												   BOOL usemipmaps,
 												   LLViewerTexture::EBoostLevel boost_priority,
@@ -290,7 +288,7 @@ LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromFile(
 }
 
 //static 
-LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const std::string& url,
+LLViewerFetchedTexture* LLViewerTextureManager::getFetchedTextureFromUrl(const std::string& url,									 
 									 FTType f_type,
 									 BOOL usemipmaps,
 									 LLViewerTexture::EBoostLevel boost_priority,
@@ -397,7 +395,7 @@ void LLViewerTextureManager::init()
 	LLViewerTexture::sCheckerBoardImagep = LLViewerTextureManager::getLocalTexture(image_raw.get(), TRUE);
 
 	LLViewerTexture::initClass() ;
-	
+
 	// Create a texture manager bridge.
 	gTextureManagerBridgep = new LLViewerTextureManagerBridge;
 
@@ -425,6 +423,7 @@ void LLViewerTextureManager::cleanup()
 	LLViewerFetchedTexture::sSmokeImagep = NULL;
 	LLViewerFetchedTexture::sMissingAssetImagep = NULL;
 	LLViewerFetchedTexture::sWhiteImagep = NULL;
+	LLViewerFetchedTexture::sFlatNormalImagep = NULL;
 
 	LLViewerMediaTexture::cleanUpClass() ;	
 }
@@ -565,8 +564,7 @@ void LLViewerTexture::updateClass(const F32 velocity, const F32 angular_velocity
 		}
 	}
 	sDesiredDiscardBias = llclamp(sDesiredDiscardBias, desired_discard_bias_min, desired_discard_bias_max);
-	LLViewerTexture::sUseTextureAtlas = gSavedSettings.getBOOL("EnableTextureAtlas") ;
-	
+		
 	F32 camera_moving_speed = LLViewerCamera::getInstance()->getAverageSpeed() ;
 	F32 camera_angular_speed = LLViewerCamera::getInstance()->getAverageAngularSpeed();
 	sCameraMovingBias = llmax(0.2f * camera_moving_speed, 2.0f * camera_angular_speed - 1);
@@ -632,9 +630,14 @@ void LLViewerTexture::init(bool firstinit)
 	mMaxVirtualSizeResetCounter = mMaxVirtualSizeResetInterval ;
 	mAdditionalDecodePriority = 0.f ;	
 	mParcelMedia = NULL ;
-	mNumFaces = 0 ;
+	
 	mNumVolumes = 0;
-	mFaceList.clear() ;
+	mFaceList[LLRender::DIFFUSE_MAP].clear() ;
+	mFaceList[LLRender::NORMAL_MAP].clear() ;
+	mFaceList[LLRender::SPECULAR_MAP].clear() ;
+	mNumFaces[LLRender::DIFFUSE_MAP] = 
+	mNumFaces[LLRender::NORMAL_MAP] = 
+	mNumFaces[LLRender::SPECULAR_MAP] = 0 ;
 	mVolumeList.clear();
 }
 
@@ -646,7 +649,9 @@ S8 LLViewerTexture::getType() const
 
 void LLViewerTexture::cleanup()
 {
-	mFaceList.clear() ;
+	mFaceList[LLRender::DIFFUSE_MAP].clear() ;
+	mFaceList[LLRender::NORMAL_MAP].clear() ;
+	mFaceList[LLRender::SPECULAR_MAP].clear() ;
 	mVolumeList.clear();
 }
 
@@ -762,38 +767,57 @@ void LLViewerTexture::setKnownDrawSize(S32 width, S32 height)
 }
 
 //virtual
-void LLViewerTexture::addFace(LLFace* facep) 
+void LLViewerTexture::addFace(U32 ch, LLFace* facep) 
 {
-	if(mNumFaces >= mFaceList.size())
+	llassert(ch < LLRender::NUM_TEXTURE_CHANNELS);
+
+	if(mNumFaces[ch] >= mFaceList[ch].size())
 	{
-		mFaceList.resize(2 * mNumFaces + 1) ;		
+		mFaceList[ch].resize(2 * mNumFaces[ch] + 1) ;		
 	}
-	mFaceList[mNumFaces] = facep ;
-	facep->setIndexInTex(mNumFaces) ;
-	mNumFaces++ ;
+	mFaceList[ch][mNumFaces[ch]] = facep ;
+	facep->setIndexInTex(ch, mNumFaces[ch]) ;
+	mNumFaces[ch]++ ;
 	mLastFaceListUpdateTimer.reset() ;
 }
 
 //virtual
-void LLViewerTexture::removeFace(LLFace* facep) 
+void LLViewerTexture::removeFace(U32 ch, LLFace* facep) 
 {
-	if(mNumFaces > 1)
+	llassert(ch < LLRender::NUM_TEXTURE_CHANNELS);
+
+	if(mNumFaces[ch] > 1)
 	{
-		S32 index = facep->getIndexInTex() ; 
-		mFaceList[index] = mFaceList[--mNumFaces] ;
-		mFaceList[index]->setIndexInTex(index) ;
+		S32 index = facep->getIndexInTex(ch) ; 
+		llassert(index < mFaceList[ch].size());
+		llassert(index < mNumFaces[ch]);
+		mFaceList[ch][index] = mFaceList[ch][--mNumFaces[ch]] ;
+		mFaceList[ch][index]->setIndexInTex(ch, index) ;
 	}
 	else 
 	{
-		mFaceList.clear() ;
-		mNumFaces = 0 ;
+		mFaceList[ch].clear() ;
+		mNumFaces[ch] = 0 ;
 	}
 	mLastFaceListUpdateTimer.reset() ;
 }
 
-S32 LLViewerTexture::getNumFaces() const
+S32 LLViewerTexture::getTotalNumFaces() const
 {
-	return mNumFaces ;
+	S32 ret = 0;
+
+	for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i)
+	{
+		ret += mNumFaces[i];
+	}
+
+	return ret;
+}
+
+S32 LLViewerTexture::getNumFaces(U32 ch) const
+{
+	llassert(ch < LLRender::NUM_TEXTURE_CHANNELS);
+	return mNumFaces[ch];
 }
 
 
@@ -816,6 +840,8 @@ void LLViewerTexture::removeVolume(LLVOVolume* volumep)
 	if(mNumVolumes > 1)
 	{
 		S32 index = volumep->getIndexInTex() ; 
+		llassert(index < mVolumeList.size());
+		llassert(index < mNumVolumes);
 		mVolumeList[index] = mVolumeList[--mNumVolumes] ;
 		mVolumeList[index]->setIndexInTex(index) ;
 	}
@@ -837,18 +863,22 @@ void LLViewerTexture::reorganizeFaceList()
 	static const F32 MAX_WAIT_TIME = 20.f; // seconds
 	static const U32 MAX_EXTRA_BUFFER_SIZE = 4 ;
 
-	if(mNumFaces + MAX_EXTRA_BUFFER_SIZE > mFaceList.size())
+	if(mLastFaceListUpdateTimer.getElapsedTimeF32() < MAX_WAIT_TIME)
 	{
-		return ;
+		return;
 	}
 
-	if(mLastFaceListUpdateTimer.getElapsedTimeF32() < MAX_WAIT_TIME)
+	for (U32 i = 0; i < LLRender::NUM_TEXTURE_CHANNELS; ++i)
 	{
-		return ;
+		if(mNumFaces[i] + MAX_EXTRA_BUFFER_SIZE > mFaceList[i].size())
+		{
+			return ;
+		}
+			
+		mFaceList[i].erase(mFaceList[i].begin() + mNumFaces[i], mFaceList[i].end());
 	}
-
+	
 	mLastFaceListUpdateTimer.reset() ;
-	mFaceList.erase(mFaceList.begin() + mNumFaces, mFaceList.end());
 }
 
 void LLViewerTexture::reorganizeVolumeList()
@@ -1177,7 +1207,7 @@ void LLViewerFetchedTexture::destroyTexture()
 	{
 		return ;
 	}
-
+	
 	//LL_DEBUGS("Avatar") << mID << llendl;
 	destroyGLTexture() ;
 	mFullyLoaded = FALSE ;
@@ -1194,9 +1224,14 @@ void LLViewerFetchedTexture::addToCreateTexture()
 		mGLTexturep->setComponents(mComponents) ;
 		force_update = true ;
 
-		for(U32 i = 0 ; i < mNumFaces ; i++)
+		for (U32 j = 0; j < LLRender::NUM_TEXTURE_CHANNELS; ++j)
 		{
-			mFaceList[i]->dirtyTexture() ;
+			llassert(mNumFaces[j] <= mFaceList[j].size());
+
+			for(U32 i = 0 ; i < mNumFaces[j]; i++)
+			{
+				mFaceList[j][i]->dirtyTexture() ;
+			}
 		}
 
 		//discard the cached raw image and the saved raw image
@@ -1340,11 +1375,8 @@ BOOL LLViewerFetchedTexture::createTexture(S32 usename/*= 0*/)
 		return FALSE;
 	}
 	
-	if(!(res = insertToAtlas()))
-	{
-		res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, TRUE, mBoostLevel);
-		resetFaceAtlas() ;
-	}
+	res = mGLTexturep->createGLTexture(mRawDiscardLevel, mRawImage, usename, TRUE, mBoostLevel);
+	
 	setActive() ;
 
 	if (!needsToSaveRawImage())
@@ -1633,28 +1665,32 @@ void LLViewerFetchedTexture::updateVirtualSize()
 		addTextureStats(0.f, FALSE) ;//reset
 	}
 
-	for(U32 i = 0 ; i < mNumFaces ; i++)
-	{				
-		LLFace* facep = mFaceList[i] ;
-		if( facep )
-		{
-			LLDrawable* drawable = facep->getDrawable();
-			if (drawable)
+	for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch)
+	{
+		llassert(mNumFaces[ch] <= mFaceList[ch].size());
+
+		for(U32 i = 0 ; i < mNumFaces[ch]; i++)
+		{				
+			LLFace* facep = mFaceList[ch][i] ;
+			if( facep )
 			{
-				if(drawable->isRecentlyVisible())
+				LLDrawable* drawable = facep->getDrawable();
+				if (drawable)
 				{
-					if (getBoostLevel() == LLViewerTexture::BOOST_NONE && 
-						drawable->getVObj() && drawable->getVObj()->isSelected())
+					if(drawable->isRecentlyVisible())
 					{
-						setBoostLevel(LLViewerTexture::BOOST_SELECTED);
+						if (getBoostLevel() == LLViewerTexture::BOOST_NONE && 
+							drawable->getVObj() && drawable->getVObj()->isSelected())
+						{
+							setBoostLevel(LLViewerTexture::BOOST_SELECTED);
+						}
+						addTextureStats(facep->getVirtualSize()) ;
+						setAdditionalDecodePriority(facep->getImportanceToCamera()) ;
 					}
-					addTextureStats(facep->getVirtualSize()) ;
-					setAdditionalDecodePriority(facep->getImportanceToCamera()) ;
 				}
 			}
 		}
 	}
-
 	//reset whether or not a face was selected after 10 seconds
 	const F32 SELECTION_RESET_TIME = 10.f;
 
@@ -2739,190 +2775,6 @@ F32 LLViewerFetchedTexture::getElapsedLastReferencedSavedRawImageTime() const
 { 
 	return sCurrentTime - mLastReferencedSavedRawImageTime ;
 }
-//----------------------------------------------------------------------------------------------
-//atlasing
-//----------------------------------------------------------------------------------------------
-void LLViewerFetchedTexture::resetFaceAtlas()
-{
-	//Nothing should be done here.
-}
-
-//invalidate all atlas slots for this image.
-void LLViewerFetchedTexture::invalidateAtlas(BOOL rebuild_geom)
-{
-	for(U32 i = 0 ; i < mNumFaces ; i++)
-	{
-		LLFace* facep = mFaceList[i] ;
-		facep->removeAtlas() ;
-		if(rebuild_geom && facep->getDrawable() && facep->getDrawable()->getSpatialGroup())
-		{
-			facep->getDrawable()->getSpatialGroup()->setState(LLSpatialGroup::GEOM_DIRTY);
-		}
-	}
-}
-
-BOOL LLViewerFetchedTexture::insertToAtlas()
-{
-	if(!LLViewerTexture::sUseTextureAtlas)
-	{
-		return FALSE ;
-	}
-	if(getNumFaces() < 1)
-	{
-		return FALSE ;
-	}						
-	if(mGLTexturep->getDiscardLevelInAtlas() > 0 && mRawDiscardLevel >= mGLTexturep->getDiscardLevelInAtlas())
-	{
-		return FALSE ;
-	}
-	if(!LLTextureAtlasManager::getInstance()->canAddToAtlas(mRawImage->getWidth(), mRawImage->getHeight(), mRawImage->getComponents(), mGLTexturep->getTexTarget()))
-	{
-		return FALSE ;
-	}
-
-	BOOL ret = TRUE ;//if ret is set to false, will generate a gl texture for this image.
-	S32 raw_w = mRawImage->getWidth() ;
-	S32 raw_h = mRawImage->getHeight() ;
-	F32 xscale = 1.0f, yscale = 1.0f ;
-	LLPointer<LLTextureAtlasSlot> slot_infop;
-	LLTextureAtlasSlot* cur_slotp ;//no need to be smart pointer.
-	LLSpatialGroup* groupp ;
-	LLFace* facep;
-
-	//if the atlas slot pointers for some faces are null, process them later.
-	ll_face_list_t waiting_list ;
-	for(U32 i = 0 ; i < mNumFaces ; i++)
-	{
-		{
-			facep = mFaceList[i] ;			
-			
-			//face can not use atlas.
-			if(!facep->canUseAtlas())
-			{
-				if(facep->getAtlasInfo())
-				{
-					facep->removeAtlas() ;	
-				}
-				ret = FALSE ;
-				continue ;
-			}
-
-			//the atlas slot is updated
-			slot_infop = facep->getAtlasInfo() ;
-			groupp = facep->getDrawable()->getSpatialGroup() ;	
-
-			if(slot_infop) 
-			{
-				if(slot_infop->getSpatialGroup() != groupp)
-				{
-					if((cur_slotp = groupp->getCurUpdatingSlot(this))) //switch slot
-					{
-						facep->setAtlasInfo(cur_slotp) ;
-						facep->setAtlasInUse(TRUE) ;
-						continue ;
-					}
-					else //do not forget to update slot_infop->getSpatialGroup().
-					{
-						LLSpatialGroup* gp = slot_infop->getSpatialGroup() ;
-						gp->setCurUpdatingTime(gFrameCount) ;
-						gp->setCurUpdatingTexture(this) ;
-						gp->setCurUpdatingSlot(slot_infop) ;
-					}
-				}
-				else //same group
-				{
-					if(gFrameCount && slot_infop->getUpdatedTime() == gFrameCount)//slot is just updated
-					{
-						facep->setAtlasInUse(TRUE) ;
-						continue ;
-					}
-				}
-			}				
-			else
-			{
-				//if the slot is null, wait to process them later.
-				waiting_list.push_back(facep) ;
-				continue ;
-			}
-						
-			//----------
-			//insert to atlas
-			if(!slot_infop->getAtlas()->insertSubTexture(mGLTexturep, mRawDiscardLevel, mRawImage, slot_infop->getSlotCol(), slot_infop->getSlotRow()))			
-			{
-				
-				//the texture does not qualify to add to atlas, do not bother to try for other faces.
-				//invalidateAtlas();
-				return FALSE ;
-			}
-			
-			//update texture scale		
-			slot_infop->getAtlas()->getTexCoordScale(raw_w, raw_h, xscale, yscale) ;
-			slot_infop->setTexCoordScale(xscale, yscale) ;
-			slot_infop->setValid() ;
-			slot_infop->setUpdatedTime(gFrameCount) ;
-			
-			//update spatial group atlas info
-			groupp->setCurUpdatingTime(gFrameCount) ;
-			groupp->setCurUpdatingTexture(this) ;
-			groupp->setCurUpdatingSlot(slot_infop) ;
-
-			//make the face to switch to the atlas.
-			facep->setAtlasInUse(TRUE) ;
-		}
-	}
-
-	//process the waiting_list
-	for(std::vector<LLFace*>::iterator iter = waiting_list.begin(); iter != waiting_list.end(); ++iter)
-	{
-		facep = (LLFace*)*iter ;	
-		groupp = facep->getDrawable()->getSpatialGroup() ;
-
-		//check if this texture already inserted to atlas for this group
-		if((cur_slotp = groupp->getCurUpdatingSlot(this)))
-		{
-			facep->setAtlasInfo(cur_slotp) ;
-			facep->setAtlasInUse(TRUE) ;		
-			continue ;
-		}
-
-		//need to reserve a slot from atlas
-		slot_infop = LLTextureAtlasManager::getInstance()->reserveAtlasSlot(llmax(mFullWidth, mFullHeight), getComponents(), groupp, this) ;	
-
-		facep->setAtlasInfo(slot_infop) ;
-		
-		groupp->setCurUpdatingTime(gFrameCount) ;
-		groupp->setCurUpdatingTexture(this) ;
-		groupp->setCurUpdatingSlot(slot_infop) ;
-
-		//slot allocation failed.
-		if(!slot_infop || !slot_infop->getAtlas())
-		{			
-			ret = FALSE ;
-			facep->setAtlasInUse(FALSE) ;
-			continue ;
-		}
-				
-		//insert to atlas
-		if(!slot_infop->getAtlas()->insertSubTexture(mGLTexturep, mRawDiscardLevel, mRawImage, slot_infop->getSlotCol(), slot_infop->getSlotRow()))
-		{
-			//the texture does not qualify to add to atlas, do not bother to try for other faces.
-			ret = FALSE ;
-			//invalidateAtlas();
-			break ; 
-		}
-		
-		//update texture scale		
-		slot_infop->getAtlas()->getTexCoordScale(raw_w, raw_h, xscale, yscale) ;
-		slot_infop->setTexCoordScale(xscale, yscale) ;
-		slot_infop->setValid() ;
-		slot_infop->setUpdatedTime(gFrameCount) ;
-
-		//make the face to switch to the atlas.
-		facep->setAtlasInUse(TRUE) ;
-	}
-	
-	return ret ;
-}
 
 //----------------------------------------------------------------------------------------------
 //end of LLViewerFetchedTexture
@@ -3269,11 +3121,14 @@ BOOL LLViewerMediaTexture::findFaces()
 	LLViewerTexture* tex = gTextureList.findImage(mID) ;
 	if(tex) //this media is a parcel media for tex.
 	{
-		const ll_face_list_t* face_list = tex->getFaceList() ;
-		U32 end = tex->getNumFaces() ;
-		for(U32 i = 0 ; i < end ; i++)
+		for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch)
 		{
-			mMediaFaceList.push_back((*face_list)[i]) ;
+			const ll_face_list_t* face_list = tex->getFaceList(ch) ;
+			U32 end = tex->getNumFaces(ch) ;
+			for(U32 i = 0 ; i < end ; i++)
+			{
+				mMediaFaceList.push_back((*face_list)[i]) ;
+			}
 		}
 	}
 	
@@ -3338,7 +3193,7 @@ void LLViewerMediaTexture::addMediaToFace(LLFace* facep)
 		return ; //no need to add the face because the media is not in playing.
 	}
 
-	switchTexture(facep) ;
+	switchTexture(LLRender::DIFFUSE_MAP, facep) ;
 }
 	
 void LLViewerMediaTexture::removeMediaFromFace(LLFace* facep) 
@@ -3355,19 +3210,19 @@ void LLViewerMediaTexture::removeMediaFromFace(LLFace* facep)
 	}	
 
 	mIsPlaying = FALSE ; //set to remove the media from the face.
-	switchTexture(facep) ;
+	switchTexture(LLRender::DIFFUSE_MAP, facep) ;
 	mIsPlaying = TRUE ; //set the flag back.
 
-	if(getNumFaces() < 1) //no face referencing to this media
+	if(getTotalNumFaces() < 1) //no face referencing to this media
 	{
 		stopPlaying() ;
 	}
 }
 
 //virtual 
-void LLViewerMediaTexture::addFace(LLFace* facep) 
+void LLViewerMediaTexture::addFace(U32 ch, LLFace* facep) 
 {
-	LLViewerTexture::addFace(facep) ;
+	LLViewerTexture::addFace(ch, facep) ;
 
 	const LLTextureEntry* te = facep->getTextureEntry() ;
 	if(te && te->getID().notNull())
@@ -3394,9 +3249,9 @@ void LLViewerMediaTexture::addFace(LLFace* facep)
 }
 
 //virtual 
-void LLViewerMediaTexture::removeFace(LLFace* facep) 
+void LLViewerMediaTexture::removeFace(U32 ch, LLFace* facep) 
 {
-	LLViewerTexture::removeFace(facep) ;
+	LLViewerTexture::removeFace(ch, facep) ;
 
 	const LLTextureEntry* te = facep->getTextureEntry() ;
 	if(te && te->getID().notNull())
@@ -3414,24 +3269,35 @@ void LLViewerMediaTexture::removeFace(LLFace* facep)
 				}
 			}
 
-			//
-			//we have some trouble here: the texture of the face is changed.
-			//we need to find the former texture, and remove it from the list to avoid memory leaking.
-			if(!mNumFaces)
+			std::vector<const LLTextureEntry*> te_list;
+			
+			for (U32 ch = 0; ch < 3; ++ch)
 			{
-				mTextureList.clear() ;
-				return ;
+				//
+				//we have some trouble here: the texture of the face is changed.
+				//we need to find the former texture, and remove it from the list to avoid memory leaking.
+				
+				llassert(mNumFaces[ch] <= mFaceList[ch].size());
+
+				for(U32 j = 0 ; j < mNumFaces[ch] ; j++)
+				{
+					te_list.push_back(mFaceList[ch][j]->getTextureEntry());//all textures are in use.
+				}
 			}
-			S32 end = getNumFaces() ;
-			std::vector<const LLTextureEntry*> te_list(end) ;
-			S32 i = 0 ;			
-			for(U32 j = 0 ; j < mNumFaces ; j++)
+
+			if (te_list.empty())
 			{
-				te_list[i++] = mFaceList[j]->getTextureEntry() ;//all textures are in use.
+				mTextureList.clear() ;
+				return ;
 			}
+
+			S32 end = te_list.size();
+
 			for(std::list< LLPointer<LLViewerTexture> >::iterator iter = mTextureList.begin();
 				iter != mTextureList.end(); ++iter)
 			{
+				S32 i = 0;
+
 				for(i = 0 ; i < end ; i++)
 				{
 					if(te_list[i] && te_list[i]->getID() == (*iter)->getID())//the texture is in use.
@@ -3476,7 +3342,7 @@ void LLViewerMediaTexture::stopPlaying()
 	mIsPlaying = FALSE ;			
 }
 
-void LLViewerMediaTexture::switchTexture(LLFace* facep)
+void LLViewerMediaTexture::switchTexture(U32 ch, LLFace* facep)
 {
 	if(facep)
 	{
@@ -3492,7 +3358,7 @@ void LLViewerMediaTexture::switchTexture(LLFace* facep)
 
 		if(mIsPlaying) //old textures switch to the media texture
 		{
-			facep->switchTexture(this) ;
+			facep->switchTexture(ch, this) ;
 		}
 		else //switch to old textures.
 		{
@@ -3508,7 +3374,7 @@ void LLViewerMediaTexture::switchTexture(LLFace* facep)
 				{
 					tex = LLViewerFetchedTexture::sDefaultImagep ;
 				}
-				facep->switchTexture(tex) ;
+				facep->switchTexture(ch, tex) ;
 			}
 		}
 	}
@@ -3547,14 +3413,17 @@ void LLViewerMediaTexture::setPlaying(BOOL playing)
 
 		for(std::list< LLFace* >::iterator iter = mMediaFaceList.begin(); iter!= mMediaFaceList.end(); ++iter)
 		{
-			switchTexture(*iter) ;
+			switchTexture(LLRender::DIFFUSE_MAP, *iter) ;
 		}
 	}
 	else //stop playing this media
 	{
-		for(U32 i = mNumFaces ; i ; i--)
+		U32 ch = LLRender::DIFFUSE_MAP;
+		
+		llassert(mNumFaces[ch] <= mFaceList[ch].size());
+		for(U32 i = mNumFaces[ch] ; i ; i--)
 		{
-			switchTexture(mFaceList[i - 1]) ; //current face could be removed in this function.
+			switchTexture(ch, mFaceList[ch][i - 1]) ; //current face could be removed in this function.
 		}
 	}
 	return ;
@@ -3576,14 +3445,18 @@ F32 LLViewerMediaTexture::getMaxVirtualSize()
 
 	if(mIsPlaying) //media is playing
 	{
-		for(U32 i = 0 ; i < mNumFaces ; i++)
+		for (U32 ch = 0; ch < LLRender::NUM_TEXTURE_CHANNELS; ++ch)
 		{
-			LLFace* facep = mFaceList[i] ;
-			if(facep->getDrawable()->isRecentlyVisible())
+			llassert(mNumFaces[ch] <= mFaceList[ch].size());
+			for(U32 i = 0 ; i < mNumFaces[ch] ; i++)
 			{
-				addTextureStats(facep->getVirtualSize()) ;
-			}
-		}		
+				LLFace* facep = mFaceList[ch][i] ;
+				if(facep->getDrawable()->isRecentlyVisible())
+				{
+					addTextureStats(facep->getVirtualSize()) ;
+				}
+			}		
+		}
 	}
 	else //media is not in playing
 	{
diff --git a/indra/newview/llviewertexture.h b/indra/newview/llviewertexture.h
index f2e1a90713afade6a10f4ed4432648eac3c8395e..c96f89017fd75d96734faecbf20383326bcd7851 100755
--- a/indra/newview/llviewertexture.h
+++ b/indra/newview/llviewertexture.h
@@ -34,6 +34,7 @@
 #include "llgltypes.h"
 #include "llrender.h"
 #include "llmetricperformancetester.h"
+#include "llface.h"
 
 #include <map>
 #include <list>
@@ -41,7 +42,6 @@
 #define MIN_VIDEO_RAM_IN_MEGA_BYTES    32
 #define MAX_VIDEO_RAM_IN_MEGA_BYTES    512 // 512MB max for performance reasons.
 
-class LLFace;
 class LLImageGL ;
 class LLImageRaw;
 class LLViewerObject;
@@ -98,7 +98,6 @@ class LLViewerTexture : public LLGLTexture
 		DYNAMIC_TEXTURE,
 		FETCHED_TEXTURE,
 		LOD_TEXTURE,
-		ATLAS_TEXTURE,
 		INVALID_TEXTURE_TYPE
 	};
 
@@ -140,12 +139,15 @@ class LLViewerTexture : public LLGLTexture
 
 	LLFrameTimer* getLastReferencedTimer() {return &mLastReferencedTimer ;}
 	
+	S32 getFullWidth() const { return mFullWidth; }
+	S32 getFullHeight() const { return mFullHeight; }	
 	/*virtual*/ void setKnownDrawSize(S32 width, S32 height);
 
-	virtual void addFace(LLFace* facep) ;
-	virtual void removeFace(LLFace* facep) ; 
-	S32 getNumFaces() const;
-	const ll_face_list_t* getFaceList() const {return &mFaceList;}
+	virtual void addFace(U32 channel, LLFace* facep) ;
+	virtual void removeFace(U32 channel, LLFace* facep) ; 
+	S32 getTotalNumFaces() const;
+	S32 getNumFaces(U32 ch) const;
+	const ll_face_list_t* getFaceList(U32 channel) const {llassert(channel < LLRender::NUM_TEXTURE_CHANNELS); return &mFaceList[channel];}
 
 	virtual void addVolume(LLVOVolume* volumep);
 	virtual void removeVolume(LLVOVolume* volumep);
@@ -182,8 +184,8 @@ class LLViewerTexture : public LLGLTexture
 	mutable F32 mAdditionalDecodePriority;  // priority add to mDecodePriority.
 	LLFrameTimer mLastReferencedTimer;	
 
-	ll_face_list_t    mFaceList ; //reverse pointer pointing to the faces using this image as texture
-	U32               mNumFaces ;
+	ll_face_list_t    mFaceList[LLRender::NUM_TEXTURE_CHANNELS]; //reverse pointer pointing to the faces using this image as texture
+	U32               mNumFaces[LLRender::NUM_TEXTURE_CHANNELS];
 	LLFrameTimer      mLastFaceListUpdateTimer ;
 
 	ll_volume_list_t  mVolumeList;
@@ -214,8 +216,7 @@ class LLViewerTexture : public LLGLTexture
 	static S32 sMaxSmallImageSize ;
 	static BOOL sFreezeImageScalingDown ;//do not scale down image res if set.
 	static F32  sCurrentTime ;
-	static BOOL sUseTextureAtlas ;
-
+	
 	enum EDebugTexels
 	{
 		DEBUG_TEXELS_OFF,
@@ -400,17 +401,12 @@ class LLViewerFetchedTexture : public LLViewerTexture
 	S32 getCurrentDiscardLevelForFetching() ;
 
 private:
-	void init(bool firstinit) ;	
+	void init(bool firstinit) ;
 	void cleanup() ;
 
 	void saveRawImage() ;
 	void setCachedRawImage() ;
 
-	//for atlas
-	void resetFaceAtlas() ;
-	void invalidateAtlas(BOOL rebuild_geom) ;
-	BOOL insertToAtlas() ;
-
 private:
 	BOOL  mFullyLoaded;
 	BOOL  mInDebug;
@@ -447,7 +443,7 @@ class LLViewerFetchedTexture : public LLViewerTexture
 	S8  mHasFetcher;				// We've made a fecth request
 	S8  mIsFetching;				// Fetch request is active
 	bool mCanUseHTTP ;              //This texture can be fetched through http if true.
-
+	
 	FTType mFTType; // What category of image is this - map tile, server bake, etc?
 	mutable S8 mIsMissingAsset;		// True if we know that there is no image asset with this image id in the database.		
 
@@ -496,6 +492,7 @@ class LLViewerFetchedTexture : public LLViewerTexture
 	static LLPointer<LLViewerFetchedTexture> sWhiteImagep;	// Texture to show NOTHING (whiteness)
 	static LLPointer<LLViewerFetchedTexture> sDefaultImagep; // "Default" texture for error cases, the only case of fetched texture which is generated in local.
 	static LLPointer<LLViewerFetchedTexture> sSmokeImagep; // Old "Default" translucent texture
+	static LLPointer<LLViewerFetchedTexture> sFlatNormalImagep; // Flat normal map denoting no bumpiness on a surface
 };
 
 //
@@ -553,12 +550,12 @@ class LLViewerMediaTexture : public LLViewerTexture
 	void addMediaToFace(LLFace* facep) ;
 	void removeMediaFromFace(LLFace* facep) ;
 
-	/*virtual*/ void addFace(LLFace* facep) ;
-	/*virtual*/ void removeFace(LLFace* facep) ; 
+	/*virtual*/ void addFace(U32 ch, LLFace* facep) ;
+	/*virtual*/ void removeFace(U32 ch, LLFace* facep) ; 
 
 	/*virtual*/ F32  getMaxVirtualSize() ;
 private:
-	void switchTexture(LLFace* facep) ;
+	void switchTexture(U32 ch, LLFace* facep) ;
 	BOOL findFaces() ;
 	void stopPlaying() ;
 
diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp
index d2af48f5286d78a95ee1eb1bd18168cddc757883..d9f3548a29d0e6e5ec8abf77f9ae479aa6bd7326 100755
--- a/indra/newview/llviewertexturelist.cpp
+++ b/indra/newview/llviewertexturelist.cpp
@@ -119,6 +119,9 @@ void LLViewerTextureList::doPreloadImages()
 	LLTexUnit::sWhiteTexture = LLViewerFetchedTexture::sWhiteImagep->getTexName();
 	LLUIImageList* image_list = LLUIImageList::getInstance();
 
+	// Set the default flat normal map
+	LLViewerFetchedTexture::sFlatNormalImagep = LLViewerTextureManager::getFetchedTextureFromFile("flatnormal.tga", FTT_LOCAL_FILE, MIPMAP_NO, LLViewerFetchedTexture::BOOST_BUMP);
+	
 	image_list->initFromFile();
 	
 	// turn off clamping and bilinear filtering for uv picking images
@@ -324,7 +327,7 @@ void LLViewerTextureList::restoreGL()
 
 ///////////////////////////////////////////////////////////////////////////////
 
-LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string& filename,
+LLViewerFetchedTexture* LLViewerTextureList::getImageFromFile(const std::string& filename,												   
 												   FTType f_type,
 												   BOOL usemipmaps,
 												   LLViewerTexture::EBoostLevel boost_priority,
@@ -376,7 +379,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string&
 	}
 
 	LLPointer<LLViewerFetchedTexture> imagep = findImage(new_id);
-
+	
 	if (!imagep.isNull())
 	{
 		LLViewerFetchedTexture *texture = imagep.get();
@@ -432,7 +435,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImageFromUrl(const std::string&
 }
 
 
-LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id,
+LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id,											       
 												   FTType f_type,
 												   BOOL usemipmaps,
 												   LLViewerTexture::EBoostLevel boost_priority,
@@ -475,7 +478,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id,
 		{
 			llwarns << "FTType mismatch: requested " << f_type << " image has " << imagep->getFTType() << llendl;
 		}
-		
+	
 	}
 	if (imagep.isNull())
 	{
@@ -488,7 +491,7 @@ LLViewerFetchedTexture* LLViewerTextureList::getImage(const LLUUID &image_id,
 }
 
 //when this function is called, there is no such texture in the gTextureList with image_id.
-LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id,
+LLViewerFetchedTexture* LLViewerTextureList::createImage(const LLUUID &image_id,											       
 												   FTType f_type,
 												   BOOL usemipmaps,
 												   LLViewerTexture::EBoostLevel boost_priority,
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index fe4d5b3e4de55c5ee5f697d63b7e521365807ea3..65a906d3c0bd2a5f39a5da3bb273d591379863c3 100755
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -229,13 +229,13 @@ LLFrameTimer	gAwayTriggerTimer;
 BOOL			gShowOverlayTitle = FALSE;
 
 LLViewerObject*  gDebugRaycastObject = NULL;
-LLVector3       gDebugRaycastIntersection;
-LLVector2       gDebugRaycastTexCoord;
-LLVector3       gDebugRaycastNormal;
-LLVector3       gDebugRaycastBinormal;
-S32				gDebugRaycastFaceHit;
-LLVector3		gDebugRaycastStart;
-LLVector3		gDebugRaycastEnd;
+LLVector4a       gDebugRaycastIntersection;
+LLVector2        gDebugRaycastTexCoord;
+LLVector4a       gDebugRaycastNormal;
+LLVector4a       gDebugRaycastTangent;
+S32				 gDebugRaycastFaceHit;
+LLVector4a		 gDebugRaycastStart;
+LLVector4a		 gDebugRaycastEnd;
 
 // HUD display lines in lower right
 BOOL				gDisplayWindInfo = FALSE;
@@ -2841,7 +2841,7 @@ void LLViewerWindow::updateUI()
 											  &gDebugRaycastIntersection,
 											  &gDebugRaycastTexCoord,
 											  &gDebugRaycastNormal,
-											  &gDebugRaycastBinormal,
+											  &gDebugRaycastTangent,
 											  &gDebugRaycastStart,
 											  &gDebugRaycastEnd);
 	}
@@ -3739,7 +3739,7 @@ LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot,  BOOL pick_trans
 }
 
 LLHUDIcon* LLViewerWindow::cursorIntersectIcon(S32 mouse_x, S32 mouse_y, F32 depth,
-										   LLVector3* intersection)
+										   LLVector4a* intersection)
 {
 	S32 x = mouse_x;
 	S32 y = mouse_y;
@@ -3751,14 +3751,17 @@ LLHUDIcon* LLViewerWindow::cursorIntersectIcon(S32 mouse_x, S32 mouse_y, F32 dep
 	}
 
 	// world coordinates of mouse
+	// VECTORIZE THIS
 	LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
 	LLVector3 mouse_point_global = LLViewerCamera::getInstance()->getOrigin();
 	LLVector3 mouse_world_start = mouse_point_global;
 	LLVector3 mouse_world_end   = mouse_point_global + mouse_direction_global * depth;
 
-	return LLHUDIcon::lineSegmentIntersectAll(mouse_world_start, mouse_world_end, intersection);
-
+	LLVector4a start, end;
+	start.load3(mouse_world_start.mV);
+	end.load3(mouse_world_end.mV);
 	
+	return LLHUDIcon::lineSegmentIntersectAll(start, end, intersection);
 }
 
 LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 depth,
@@ -3766,12 +3769,12 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de
 												S32 this_face,
 												BOOL pick_transparent,
 												S32* face_hit,
-												LLVector3 *intersection,
+												LLVector4a *intersection,
 												LLVector2 *uv,
-												LLVector3 *normal,
-												LLVector3 *binormal,
-												LLVector3* start,
-												LLVector3* end)
+												LLVector4a *normal,
+												LLVector4a *tangent,
+												LLVector4a* start,
+												LLVector4a* end)
 {
 	S32 x = mouse_x;
 	S32 y = mouse_y;
@@ -3806,17 +3809,27 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de
 	if (!LLViewerJoystick::getInstance()->getOverrideCamera())
 	{ //always set raycast intersection to mouse_world_end unless
 		//flycam is on (for DoF effect)
-		gDebugRaycastIntersection = mouse_world_end;
+		gDebugRaycastIntersection.load3(mouse_world_end.mV);
 	}
 
+	LLVector4a mw_start;
+	mw_start.load3(mouse_world_start.mV);
+	LLVector4a mw_end;
+	mw_end.load3(mouse_world_end.mV);
+
+	LLVector4a mh_start;
+	mh_start.load3(mouse_hud_start.mV);
+	LLVector4a mh_end;
+	mh_end.load3(mouse_hud_end.mV);
+
 	if (start)
 	{
-		*start = mouse_world_start;
+		*start = mw_start;
 	}
 
 	if (end)
 	{
-		*end = mouse_world_end;
+		*end = mw_end;
 	}
 
 	LLViewerObject* found = NULL;
@@ -3825,16 +3838,16 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de
 	{
 		if (this_object->isHUDAttachment()) // is a HUD object?
 		{
-			if (this_object->lineSegmentIntersect(mouse_hud_start, mouse_hud_end, this_face, pick_transparent,
-												  face_hit, intersection, uv, normal, binormal))
+			if (this_object->lineSegmentIntersect(mh_start, mh_end, this_face, pick_transparent,
+												  face_hit, intersection, uv, normal, tangent))
 			{
 				found = this_object;
 			}
 		}
 		else // is a world object
 		{
-			if (this_object->lineSegmentIntersect(mouse_world_start, mouse_world_end, this_face, pick_transparent,
-												  face_hit, intersection, uv, normal, binormal))
+			if (this_object->lineSegmentIntersect(mw_start, mw_end, this_face, pick_transparent,
+												  face_hit, intersection, uv, normal, tangent))
 			{
 				found = this_object;
 			}
@@ -3842,20 +3855,20 @@ LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 de
 	}
 	else // check ALL objects
 	{
-		found = gPipeline.lineSegmentIntersectInHUD(mouse_hud_start, mouse_hud_end, pick_transparent,
-													face_hit, intersection, uv, normal, binormal);
+		found = gPipeline.lineSegmentIntersectInHUD(mh_start, mh_end, pick_transparent,
+													face_hit, intersection, uv, normal, tangent);
 
 		if (!found) // if not found in HUD, look in world:
 		{
-			found = gPipeline.lineSegmentIntersectInWorld(mouse_world_start, mouse_world_end, pick_transparent,
-														  face_hit, intersection, uv, normal, binormal);
+			found = gPipeline.lineSegmentIntersectInWorld(mw_start, mw_end, pick_transparent,
+														  face_hit, intersection, uv, normal, tangent);
 			if (found && !pick_transparent)
 			{
 				gDebugRaycastIntersection = *intersection;
 			}
 		}
 	}
-
+		
 	return found;
 }
 
@@ -5112,6 +5125,7 @@ LLPickInfo::LLPickInfo()
 	  mXYCoords(-1, -1),
 	  mIntersection(),
 	  mNormal(),
+	  mTangent(),
 	  mBinormal(),
 	  mHUDIcon(NULL),
 	  mPickTransparent(FALSE)
@@ -5133,6 +5147,7 @@ LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos,
 	  mSTCoords(-1.f, -1.f),
 	  mXYCoords(-1, -1),
 	  mNormal(),
+	  mTangent(),
 	  mBinormal(),
 	  mHUDIcon(NULL),
 	  mPickTransparent(pick_transparent)
@@ -5143,19 +5158,26 @@ void LLPickInfo::fetchResults()
 {
 
 	S32 face_hit = -1;
-	LLVector3 intersection, normal, binormal;
+	LLVector4a intersection, normal;
+	LLVector4a tangent;
+
 	LLVector2 uv;
 
 	LLHUDIcon* hit_icon = gViewerWindow->cursorIntersectIcon(mMousePt.mX, mMousePt.mY, 512.f, &intersection);
 	
+	LLVector4a origin;
+	origin.load3(LLViewerCamera::getInstance()->getOrigin().mV);
 	F32 icon_dist = 0.f;
 	if (hit_icon)
 	{
-		icon_dist = (LLViewerCamera::getInstance()->getOrigin()-intersection).magVec();
+		LLVector4a delta;
+		delta.setSub(intersection, origin);
+		icon_dist = delta.getLength3().getF32();
 	}
+
 	LLViewerObject* hit_object = gViewerWindow->cursorIntersect(mMousePt.mX, mMousePt.mY, 512.f,
 									NULL, -1, mPickTransparent, &face_hit,
-									&intersection, &uv, &normal, &binormal);
+									&intersection, &uv, &normal, &tangent);
 	
 	mPickPt = mMousePt;
 
@@ -5165,9 +5187,13 @@ void LLPickInfo::fetchResults()
 	
 	LLViewerObject* objectp = hit_object;
 
+
+	LLVector4a delta;
+	delta.setSub(origin, intersection);
+
 	if (hit_icon && 
 		(!objectp || 
-		icon_dist < (LLViewerCamera::getInstance()->getOrigin()-intersection).magVec()))
+		icon_dist < delta.getLength3().getF32()))
 	{
 		// was this name referring to a hud icon?
 		mHUDIcon = hit_icon;
@@ -5204,11 +5230,16 @@ void LLPickInfo::fetchResults()
 			{
 				mPickType = PICK_OBJECT;
 			}
-			mObjectOffset = gAgentCamera.calcFocusOffset(objectp, intersection, mPickPt.mX, mPickPt.mY);
+
+			LLVector3 v_intersection(intersection.getF32ptr());
+
+			mObjectOffset = gAgentCamera.calcFocusOffset(objectp, v_intersection, mPickPt.mX, mPickPt.mY);
 			mObjectID = objectp->mID;
 			mObjectFace = (te_offset == NO_FACE) ? -1 : (S32)te_offset;
 
-			mPosGlobal = gAgent.getPosGlobalFromAgent(intersection);
+			
+
+			mPosGlobal = gAgent.getPosGlobalFromAgent(v_intersection);
 			
 			if (mWantSurfaceInfo)
 			{
@@ -5252,7 +5283,16 @@ void LLPickInfo::getSurfaceInfo()
 	mIntersection = LLVector3(0,0,0);
 	mNormal       = LLVector3(0,0,0);
 	mBinormal     = LLVector3(0,0,0);
+	mTangent	  = LLVector4(0,0,0,0);
 	
+	LLVector4a tangent;
+	LLVector4a intersection;
+	LLVector4a normal;
+
+	tangent.clear();
+	normal.clear();
+	intersection.clear();
+
 	LLViewerObject* objectp = getObject();
 
 	if (objectp)
@@ -5260,10 +5300,10 @@ void LLPickInfo::getSurfaceInfo()
 		if (gViewerWindow->cursorIntersect(llround((F32)mMousePt.mX), llround((F32)mMousePt.mY), 1024.f,
 										   objectp, -1, mPickTransparent,
 										   &mObjectFace,
-										   &mIntersection,
+										   &intersection,
 										   &mSTCoords,
-										   &mNormal,
-										   &mBinormal))
+										   &normal,
+										   &tangent))
 		{
 			// if we succeeded with the intersect above, compute the texture coordinates:
 
@@ -5272,10 +5312,26 @@ void LLPickInfo::getSurfaceInfo()
 				LLFace* facep = objectp->mDrawable->getFace(mObjectFace);
 				if (facep)
 				{
-				mUVCoords = facep->surfaceToTexture(mSTCoords, mIntersection, mNormal);
-			}
+					mUVCoords = facep->surfaceToTexture(mSTCoords, intersection, normal);
+				}
 			}
 
+			mIntersection.set(intersection.getF32ptr());
+			mNormal.set(normal.getF32ptr());
+			mTangent.set(tangent.getF32ptr());
+
+			//extrapoloate binormal from normal and tangent
+			
+			LLVector4a binormal;
+			binormal.setCross3(normal, tangent);
+			binormal.mul(tangent.getF32ptr()[3]);
+
+			mBinormal.set(binormal.getF32ptr());
+
+			mBinormal.normalize();
+			mNormal.normalize();
+			mTangent.normalize();
+
 			// and XY coords:
 			updateXYCoords();
 			
diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h
index b33488fd785568195eef95dc5c3192c6225aaea0..89f6e3bc26e7194b7de436342ad8204146b9b3f2 100755
--- a/indra/newview/llviewerwindow.h
+++ b/indra/newview/llviewerwindow.h
@@ -115,6 +115,7 @@ class LLPickInfo
 	LLVector2       mSTCoords;
 	LLCoordScreen	mXYCoords;
 	LLVector3		mNormal;
+	LLVector4		mTangent;
 	LLVector3		mBinormal;
 	BOOL			mPickTransparent;
 	void		    getSurfaceInfo();
@@ -357,19 +358,19 @@ class LLViewerWindow : public LLWindowCallbacks
 	void			pickAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback)(const LLPickInfo& pick_info), BOOL pick_transparent = FALSE);
 	LLPickInfo		pickImmediate(S32 x, S32 y, BOOL pick_transparent);
 	LLHUDIcon* cursorIntersectIcon(S32 mouse_x, S32 mouse_y, F32 depth,
-										   LLVector3* intersection);
+										   LLVector4a* intersection);
 
 	LLViewerObject* cursorIntersect(S32 mouse_x = -1, S32 mouse_y = -1, F32 depth = 512.f,
 									LLViewerObject *this_object = NULL,
 									S32 this_face = -1,
 									BOOL pick_transparent = FALSE,
 									S32* face_hit = NULL,
-									LLVector3 *intersection = NULL,
+									LLVector4a *intersection = NULL,
 									LLVector2 *uv = NULL,
-									LLVector3 *normal = NULL,
-									LLVector3 *binormal = NULL,
-									LLVector3* start = NULL,
-									LLVector3* end = NULL);
+									LLVector4a *normal = NULL,
+									LLVector4a *tangent = NULL,
+									LLVector4a* start = NULL,
+									LLVector4a* end = NULL);
 	
 	
 	// Returns a pointer to the last object hit
@@ -499,13 +500,13 @@ extern LLFrameTimer		gAwayTimer;				// tracks time before setting the avatar awa
 extern LLFrameTimer		gAwayTriggerTimer;		// how long the avatar has been away
 
 extern LLViewerObject*  gDebugRaycastObject;
-extern LLVector3        gDebugRaycastIntersection;
+extern LLVector4a       gDebugRaycastIntersection;
 extern LLVector2        gDebugRaycastTexCoord;
-extern LLVector3        gDebugRaycastNormal;
-extern LLVector3        gDebugRaycastBinormal;
+extern LLVector4a       gDebugRaycastNormal;
+extern LLVector4a       gDebugRaycastTangent;
 extern S32				gDebugRaycastFaceHit;
-extern LLVector3		gDebugRaycastStart;
-extern LLVector3		gDebugRaycastEnd;
+extern LLVector4a		gDebugRaycastStart;
+extern LLVector4a		gDebugRaycastEnd;
 
 extern BOOL			gDisplayCameraPos;
 extern BOOL			gDisplayWindInfo;
diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp
index 06fb23b84b3a5fdc16d7220e3924108273a282d7..1a050800b4c61168ea20c8cebce4a289abb06b77 100755
--- a/indra/newview/llvoavatar.cpp
+++ b/indra/newview/llvoavatar.cpp
@@ -802,17 +802,17 @@ void LLVOAvatar::debugAvatarRezTime(std::string notification_name, std::string c
 //------------------------------------------------------------------------
 LLVOAvatar::~LLVOAvatar()
 {
-	if (!mFullyLoaded)
-	{
+		if (!mFullyLoaded)
+		{
 		debugAvatarRezTime("AvatarRezLeftCloudNotification","left after ruth seconds as cloud");
-	}
-	else
-	{
+		}
+		else
+		{
 		debugAvatarRezTime("AvatarRezLeftNotification","left sometime after declouding");
-	}
+		}
 
 	logPendingPhases();
-	
+
 	lldebugs << "LLVOAvatar Destructor (0x" << this << ") id:" << mID << llendl;
 
 	std::for_each(mAttachmentPoints.begin(), mAttachmentPoints.end(), DeletePairedPointer());
@@ -1196,7 +1196,7 @@ void LLVOAvatar::initInstance(void)
 		registerMotion( ANIM_AGENT_TARGET,					LLTargetingMotion::create );
 		registerMotion( ANIM_AGENT_WALK_ADJUST,				LLWalkAdjustMotion::create );
 	}
-
+	
 	LLAvatarAppearance::initInstance();
 	
 	// preload specific motions here
@@ -1388,19 +1388,20 @@ void LLVOAvatar::renderCollisionVolumes()
 
 	if (mNameText.notNull())
 	{
-		LLVector3 unused;
-		mNameText->lineSegmentIntersect(LLVector3(0,0,0), LLVector3(0,0,1), unused, TRUE);
+		LLVector4a unused;
+	
+		mNameText->lineSegmentIntersect(unused, unused, unused, TRUE);
 	}
 }
 
-BOOL LLVOAvatar::lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
+BOOL LLVOAvatar::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
 									  S32 face,
 									  BOOL pick_transparent,
 									  S32* face_hit,
-									  LLVector3* intersection,
+									  LLVector4a* intersection,
 									  LLVector2* tex_coord,
-									  LLVector3* normal,
-									  LLVector3* bi_normal)
+									  LLVector4a* normal,
+									  LLVector4a* tangent)
 {
 	if ((isSelf() && !gAgent.needsRenderAvatar()) || !LLPipeline::sPickAvatar)
 	{
@@ -1417,8 +1418,8 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
 			glh::matrix4f inverse = mat.inverse();
 			glh::matrix4f norm_mat = inverse.transpose();
 
-			glh::vec3f p1(start.mV);
-			glh::vec3f p2(end.mV);
+			glh::vec3f p1(start.getF32ptr());
+			glh::vec3f p2(end.getF32ptr());
 
 			inverse.mult_matrix_vec(p1);
 			inverse.mult_matrix_vec(p2);
@@ -1437,12 +1438,12 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
 
 				if (intersection)
 				{
-					*intersection = LLVector3(res_pos.v);
+					intersection->load3(res_pos.v);
 				}
 
 				if (normal)
 				{
-					*normal = LLVector3(res_norm.v);
+					normal->load3(res_norm.v);
 				}
 
 				return TRUE;
@@ -1478,7 +1479,7 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
 
 	
 	
-	LLVector3 position;
+	LLVector4a position;
 	if (mNameText.notNull() && mNameText->lineSegmentIntersect(start, end, position))
 	{
 		if (intersection)
@@ -1492,14 +1493,14 @@ BOOL LLVOAvatar::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
 	return FALSE;
 }
 
-LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector3& start, const LLVector3& end,
+LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector4a& start, const LLVector4a& end,
 									  S32 face,
 									  BOOL pick_transparent,
 									  S32* face_hit,
-									  LLVector3* intersection,
+									  LLVector4a* intersection,
 									  LLVector2* tex_coord,
-									  LLVector3* normal,
-									  LLVector3* bi_normal)
+									  LLVector4a* normal,
+									  LLVector4a* tangent)
 {
 	if (isSelf() && !gAgent.needsRenderAvatar())
 	{
@@ -1510,8 +1511,8 @@ LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector
 
 	if (lineSegmentBoundingBox(start, end))
 	{
-		LLVector3 local_end = end;
-		LLVector3 local_intersection;
+		LLVector4a local_end = end;
+		LLVector4a local_intersection;
 
 		for (attachment_map_t::iterator iter = mAttachmentPoints.begin(); 
 			iter != mAttachmentPoints.end();
@@ -1525,7 +1526,7 @@ LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector
 			{
 				LLViewerObject* attached_object = (*attachment_iter);
 					
-				if (attached_object->lineSegmentIntersect(start, local_end, face, pick_transparent, face_hit, &local_intersection, tex_coord, normal, bi_normal))
+				if (attached_object->lineSegmentIntersect(start, local_end, face, pick_transparent, face_hit, &local_intersection, tex_coord, normal, tangent))
 				{
 					local_end = local_intersection;
 					if (intersection)
@@ -1542,7 +1543,7 @@ LLViewerObject* LLVOAvatar::lineSegmentIntersectRiggedAttachments(const LLVector
 	return hit;
 }
 
-	
+
 LLVOAvatar* LLVOAvatar::asAvatar()
 {
 	return this;
@@ -1877,22 +1878,22 @@ LLViewerFetchedTexture *LLVOAvatar::getBakedTextureImage(const U8 te, const LLUU
 	}
 
 	if (!result)
-	{
+{
 		const std::string url = getImageURL(te,uuid);
 		if (!url.empty())
-		{
+	{
 			LL_DEBUGS("Avatar") << avString() << "from URL " << url << llendl;
 			result = LLViewerTextureManager::getFetchedTextureFromUrl(
 				url, FTT_SERVER_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, uuid);
-		}
-		else
-		{
+	}
+	else
+	{
 			LL_DEBUGS("Avatar") << avString() << "from host " << uuid << llendl;
 			LLHost host = getObjectHost();
 			result = LLViewerTextureManager::getFetchedTexture(
 				uuid, FTT_HOST_BAKE, TRUE, LLGLTexture::BOOST_NONE, LLViewerTexture::LOD_TEXTURE, 0, 0, host);
-		}
 	}
+}
 	return result;
 }
 
@@ -3979,7 +3980,7 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass)
 		{
 			LLViewerJoint* hair_mesh = getViewerJoint(MESH_ID_HAIR);
 			if (hair_mesh)
-			{
+		{
 				num_indices += hair_mesh->render(mAdjustedPixelArea, first_pass, mIsDummy);
 			}
 			first_pass = FALSE;
@@ -3989,7 +3990,7 @@ U32 LLVOAvatar::renderTransparent(BOOL first_pass)
 			gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
 		}
 	}
-
+	
 	return num_indices;
 }
 
@@ -5106,9 +5107,9 @@ BOOL LLVOAvatar::loadSkeletonNode ()
 {
 	if (!LLAvatarAppearance::loadSkeletonNode())
 	{
-		return FALSE;
-	}
-
+				return FALSE;
+			}
+	
 	// ATTACHMENTS
 	{
 		LLAvatarXmlInfo::attachment_info_list_t::iterator iter;
@@ -5825,24 +5826,26 @@ BOOL LLVOAvatar::isWearingWearableType(LLWearableType::EType type) const
 	{
 		const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = tex_iter->second;
 		if (texture_dict->mWearableType == type)
-		{
+	{
 			// Thus, you must check to see if the corresponding baked texture is defined.
 			// NOTE: this is a poor substitute if you actually want to know about individual pieces of clothing
 			// this works for detecting a skirt (most important), but is ineffective at any piece of clothing that
 			// gets baked into a texture that always exists (upper or lower).
 			if (texture_dict->mIsUsedByBakedTexture)
-			{
+	{
 				const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
 				return isTextureDefined(LLAvatarAppearanceDictionary::getInstance()->getBakedTexture(baked_index)->mTextureIndex);
-			}
+	}
 			return FALSE;
-		}
+	}
 	}
 	return FALSE;
 }
 
 
 
+
+
 // virtual
 void LLVOAvatar::invalidateComposite( LLTexLayerSet* layerset, BOOL upload_result )
 {
@@ -5877,7 +5880,7 @@ void LLVOAvatar::onGlobalColorChanged(const LLTexGlobalColor* global_color, BOOL
 			{
 				LLAvatarJointMesh* mesh = (*iter);
 				if (mesh)
-				{
+			{
 					mesh->setColor( color );
 				}
 			}
@@ -5945,9 +5948,9 @@ void LLVOAvatar::updateRezzedStatusTimers()
 		{
 			// load level has decreased. start phase timers for higher load levels.
 			for (S32 i = rez_status+1; i <= mLastRezzedStatus; i++)
-			{
+		{
 				startPhase("load_" + LLVOAvatar::rezStatusToString(i));
-			}
+		}
 		}
 		else if (rez_status > mLastRezzedStatus)
 		{
@@ -5956,16 +5959,16 @@ void LLVOAvatar::updateRezzedStatusTimers()
 			{
 				stopPhase("load_" + LLVOAvatar::rezStatusToString(i));
 				stopPhase("first_load_" + LLVOAvatar::rezStatusToString(i), false);
-			}
+		}
 			if (rez_status == 3)
-			{
+		{
 				// "fully loaded", mark any pending appearance change complete.
 				selfStopPhase("update_appearance_from_cof");
 				selfStopPhase("wear_inventory_category", false);
 				selfStopPhase("process_initial_wearables_update", false);
 			}
 		}
-
+		
 		mLastRezzedStatus = rez_status;
 	}
 }
@@ -5992,7 +5995,7 @@ void LLVOAvatar::startPhase(const std::string& phase_name)
 }
 
 void LLVOAvatar::stopPhase(const std::string& phase_name, bool err_check)
-{
+		{
 	F32 elapsed;
 	bool completed;
 	if (getPhases().getPhaseValues(phase_name, elapsed, completed))
@@ -6024,7 +6027,7 @@ void LLVOAvatar::stopPhase(const std::string& phase_name, bool err_check)
 void LLVOAvatar::logPendingPhases()
 {
 	if (!isAgentAvatarValid())
-	{
+		{
 		return;
 	}
 	
@@ -6040,14 +6043,14 @@ void LLVOAvatar::logPendingPhases()
 			if (!completed)
 			{
 				logMetricsTimerRecord(phase_name, elapsed, completed);
-			}
+		}
 		}
 	}
-}
+		}
 
 //static
 void LLVOAvatar::logPendingPhasesAllAvatars()
-{
+		{
 	for (std::vector<LLCharacter*>::iterator iter = LLCharacter::sInstances.begin();
 		 iter != LLCharacter::sInstances.end(); ++iter)
 	{
@@ -6058,14 +6061,14 @@ void LLVOAvatar::logPendingPhasesAllAvatars()
 		}
 		inst->logPendingPhases();
 	}
-}
+		}
 
 void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapsed, bool completed)
-{
+		{
 	if (!isAgentAvatarValid())
-	{
+		{
 		return;
-	}
+		}
 	
 	LLSD record;
 	record["timer_name"] = phase_name;
@@ -6074,15 +6077,15 @@ void LLVOAvatar::logMetricsTimerRecord(const std::string& phase_name, F32 elapse
 	record["completed"] = completed;
 	U32 grid_x(0), grid_y(0);
 	if (getRegion())
-	{
+		{
 		record["central_bake_version"] = LLSD::Integer(getRegion()->getCentralBakeVersion());
 		grid_from_region_handle(getRegion()->getHandle(), &grid_x, &grid_y);
-	}
+		}
 	record["grid_x"] = LLSD::Integer(grid_x);
 	record["grid_y"] = LLSD::Integer(grid_y);
 	record["is_using_server_bakes"] = ((bool) isUsingServerBakes());
 	record["is_self"] = isSelf();
-	
+		
 	if (isAgentAvatarValid())
 	{
 		gAgentAvatarp->addMetricsTimerRecord(record);
@@ -6290,28 +6293,28 @@ void LLVOAvatar::updateMeshTextures()
 										   use_lkg_baked_layer[i],
 										   last_id_string.c_str());
 	}
-	
+
 	for (U32 i=0; i < mBakedTextureDatas.size(); i++)
 	{
 		debugColorizeSubMeshes(i, LLColor4::white);
 
 		LLViewerTexLayerSet* layerset = getTexLayerSet(i);
 		if (use_lkg_baked_layer[i] && !isUsingLocalAppearance() )
-		{
+	{
 			LLViewerFetchedTexture* baked_img = LLViewerTextureManager::getFetchedTexture(mBakedTextureDatas[i].mLastTextureID);
 			mBakedTextureDatas[i].mIsUsed = TRUE;
 
 			debugColorizeSubMeshes(i,LLColor4::red);
-
+	
 			avatar_joint_mesh_list_t::iterator iter = mBakedTextureDatas[i].mJointMeshes.begin();
 			avatar_joint_mesh_list_t::iterator end  = mBakedTextureDatas[i].mJointMeshes.end();
 			for (; iter != end; ++iter)
-			{
+	{
 				LLAvatarJointMesh* mesh = (*iter);
 				if (mesh)
-				{
+		{
 					mesh->setTexture( baked_img );
-				}
+			}
 			}
 		}
 		else if (!isUsingLocalAppearance() && is_layer_baked[i])
@@ -6355,7 +6358,7 @@ void LLVOAvatar::updateMeshTextures()
 				if (mesh)
 				{
 					mesh->setLayerSet( layerset );
-				}
+			}
 			}
 		}
 		else
@@ -6377,7 +6380,7 @@ void LLVOAvatar::updateMeshTextures()
 		{
 			LLAvatarJointMesh* mesh = (*iter);
 			if (mesh)
-			{
+		{
 				mesh->setColor( color );
 				mesh->setTexture( hair_img );
 			}
@@ -6465,17 +6468,18 @@ void LLVOAvatar::applyMorphMask(U8* tex_data, S32 width, S32 height, S32 num_com
 
 	for (morph_list_t::const_iterator iter = mBakedTextureDatas[index].mMaskedMorphs.begin();
 		 iter != mBakedTextureDatas[index].mMaskedMorphs.end(); ++iter)
-	{
+{
 		const LLMaskedMorph* maskedMorph = (*iter);
 		LLPolyMorphTarget* morph_target = dynamic_cast<LLPolyMorphTarget*>(maskedMorph->mMorphTarget);
 		if (morph_target)
-		{
+	{
 			morph_target->applyMask(tex_data, width, height, num_components, maskedMorph->mInvert);
-		}
+}
 	}
 }
 
 
+
 // returns TRUE if morph masks are present and not valid for a given baked texture, FALSE otherwise
 BOOL LLVOAvatar::morphMaskNeedsUpdate(LLAvatarAppearanceDefines::EBakedTextureIndex index)
 {
@@ -6753,12 +6757,12 @@ void dump_visual_param(apr_file_t* file, LLVisualParam* viewer_param, F32 value)
 					LLWearableType::getTypeName(LLWearableType::EType(wtype)).c_str()
 //					param_location_name(vparam->getParamLocation()).c_str()
 		);
-}
-
+	}
+	
 
 void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,
 	const LLAppearanceMessageContents& contents)
-{
+	{
 	std::string outfilename = get_sequential_numbered_file_name(dump_prefix,".xml");
 	const std::vector<F32>& params_for_dump = contents.mParamWeights;
 	const LLTEContents& tec = contents.mTEContents;
@@ -6768,9 +6772,9 @@ void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,
 	outfile.open(fullpath, LL_APR_WB );
 	apr_file_t* file = outfile.getFileHandle();
 	if (!file)
-	{
-		return;
-	}
+		{
+			return;
+		}
 	else
 	{
 		LL_DEBUGS("Avatar") << "dumping appearance message to " << fullpath << llendl;
@@ -6804,7 +6808,7 @@ void LLVOAvatar::dumpAppearanceMsgParams( const std::string& dump_prefix,
 		apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", i, uuid_str.c_str());
 	}
 	apr_file_printf(file, "</textures>\n");
-}
+	}
 
 void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMessageContents& contents)
 {
@@ -6821,7 +6825,7 @@ void LLVOAvatar::parseAppearanceMessage(LLMessageSystem* mesgsys, LLAppearanceMe
 		// For future use:
 		//mesgsys->getU32Fast(_PREHASH_AppearanceData, _PREHASH_Flags, appearance_flags, 0);
 	}
-
+	
 	// Parse visual params, if any.
 	S32 num_blocks = mesgsys->getNumberOfBlocksFast(_PREHASH_VisualParam);
 	bool drop_visual_params_debug = gSavedSettings.getBOOL("BlockSomeAvatarAppearanceVisualParams") && (ll_rand(2) == 0); // pretend that ~12% of AvatarAppearance messages arrived without a VisualParam block, for testing
@@ -7049,19 +7053,19 @@ void LLVOAvatar::processAvatarAppearance( LLMessageSystem* mesgsys )
 			LLVisualParam* param = contents.mParams[i];
 			F32 newWeight = contents.mParamWeights[i];
 
-			if (is_first_appearance_message || (param->getWeight() != newWeight))
-			{
-				params_changed = TRUE;
-				if(is_first_appearance_message)
+				if (is_first_appearance_message || (param->getWeight() != newWeight))
 				{
-					param->setWeight(newWeight, FALSE);
-				}
-				else
-				{
-					interp_params = TRUE;
-					param->setAnimationTarget(newWeight, FALSE);
+					params_changed = TRUE;
+					if(is_first_appearance_message)
+					{
+						param->setWeight(newWeight, FALSE);
+					}
+					else
+					{
+						interp_params = TRUE;
+						param->setAnimationTarget(newWeight, FALSE);
+					}
 				}
-			}
 		}
 		const S32 expected_tweakable_count = getVisualParamCountInGroup(VISUAL_PARAM_GROUP_TWEAKABLE); // don't worry about VISUAL_PARAM_GROUP_TWEAKABLE_NO_TRANSMIT
 		if (num_params != expected_tweakable_count)
@@ -7317,12 +7321,12 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id )
 				avatar_joint_mesh_list_t::iterator iter = mBakedTextureDatas[i].mJointMeshes.begin();
 				avatar_joint_mesh_list_t::iterator end  = mBakedTextureDatas[i].mJointMeshes.end();
 				for (; iter != end; ++iter)
-				{
+			{
 					LLAvatarJointMesh* mesh = (*iter);
 					if (mesh)
-					{
+			{
 						mesh->setTexture( image_baked );
-					}
+			}
 				}
 			}
 			
@@ -7346,7 +7350,7 @@ void LLVOAvatar::useBakedTexture( const LLUUID& id )
 				{
 					LLAvatarJointMesh* mesh = (*iter);
 					if (mesh)
-					{
+				{
 						mesh->setColor( LLColor4::white );
 					}
 				}
@@ -7365,7 +7369,7 @@ std::string get_sequential_numbered_file_name(const std::string& prefix,
 	file_num_type::iterator it = file_nums.find(prefix);
 	S32 num = 0;
 	if (it != file_nums.end())
-	{
+{
 		num = it->second;
 	}
 	file_nums[prefix] = num+1;
@@ -7382,6 +7386,10 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
 		outprefix = getFullname() + (isSelf()?"_s":"_o");
 	}
 	if (outprefix.empty())
+{
+		outprefix = getFullname() + (isSelf()?"_s":"_o");
+	}
+	if (outprefix.empty())
 	{
 		outprefix = std::string("new_archetype");
 	}
@@ -7407,36 +7415,36 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
 	if (group_by_wearables)
 	{
 		for (S32 type = LLWearableType::WT_SHAPE; type < LLWearableType::WT_COUNT; type++)
-		{
-			const std::string& wearable_name = LLWearableType::getTypeName((LLWearableType::EType)type);
-			apr_file_printf( file, "\n\t\t<!-- wearable: %s -->\n", wearable_name.c_str() );
+	{
+		const std::string& wearable_name = LLWearableType::getTypeName((LLWearableType::EType)type);
+		apr_file_printf( file, "\n\t\t<!-- wearable: %s -->\n", wearable_name.c_str() );
 
 			for (LLVisualParam* param = getFirstVisualParam(); param; param = getNextVisualParam())
+		{
+			LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param;
+			if( (viewer_param->getWearableType() == type) && 
+				(viewer_param->isTweakable() ) )
 			{
-				LLViewerVisualParam* viewer_param = (LLViewerVisualParam*)param;
-				if( (viewer_param->getWearableType() == type) && 
-					(viewer_param->isTweakable() ) )
-				{
 					dump_visual_param(file, viewer_param, viewer_param->getWeight());
-				}
 			}
+		}
 
-			for (U8 te = 0; te < TEX_NUM_INDICES; te++)
-			{
+		for (U8 te = 0; te < TEX_NUM_INDICES; te++)
+		{
 				if (LLAvatarAppearanceDictionary::getTEWearableType((ETextureIndex)te) == type)
-				{
-					// MULTIPLE_WEARABLES: extend to multiple wearables?
+			{
+				// MULTIPLE_WEARABLES: extend to multiple wearables?
 					LLViewerTexture* te_image = getImage((ETextureIndex)te, 0);
-					if( te_image )
-					{
-						std::string uuid_str;
-						te_image->getID().toString( uuid_str );
-						apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", te, uuid_str.c_str());
-					}
+				if( te_image )
+				{
+					std::string uuid_str;
+					te_image->getID().toString( uuid_str );
+					apr_file_printf( file, "\t\t<texture te=\"%i\" uuid=\"%s\"/>\n", te, uuid_str.c_str());
 				}
 			}
 		}
 	}
+		}
 	else 
 	{
 		// Just dump all params sequentially.
@@ -7448,7 +7456,6 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
 
 		for (U8 te = 0; te < TEX_NUM_INDICES; te++)
 		{
-			{
 				// MULTIPLE_WEARABLES: extend to multiple wearables?
 				LLViewerTexture* te_image = getImage((ETextureIndex)te, 0);
 				if( te_image )
@@ -7460,7 +7467,6 @@ void LLVOAvatar::dumpArchetypeXML(const std::string& prefix, bool group_by_weara
 			}
 		}
 
-	}
 	apr_file_printf( file, "\t</archetype>\n" );
 	apr_file_printf( file, "\n</linden_genepool>\n" );
 
@@ -7582,14 +7588,14 @@ void LLVOAvatar::startAppearanceAnimation()
 	}
 }
 
-//virtual
+// virtual
 void LLVOAvatar::bodySizeChanged()
-{
+{	
 	if (isSelf() && !LLAppearanceMgr::instance().isInUpdateAppearanceFromCOF())
 	{	// notify simulator of change in size
 		// but not if we are in the middle of updating appearance
 		gAgent.sendAgentSetAppearance();
-	}
+}
 }
 
 BOOL LLVOAvatar::isUsingServerBakes() const
@@ -7601,25 +7607,25 @@ BOOL LLVOAvatar::isUsingServerBakes() const
 	F32 wt = appearance_version_param->getWeight();
 	F32 expect_wt = mUseServerBakes ? 1.0 : 0.0;
 	if (!is_approx_equal(wt,expect_wt))
-	{
+{
 		llwarns << "wt " << wt << " differs from expected " << expect_wt << llendl;
 	}
 #endif
 
 	return mUseServerBakes;
-}
-
+		}
+		
 void LLVOAvatar::setIsUsingServerBakes(BOOL newval)
-{
+		{
 	mUseServerBakes = newval;
 	LLVisualParam* appearance_version_param = getVisualParam(11000);
 	llassert(appearance_version_param);
 	appearance_version_param->setWeight(newval ? 1.0 : 0.0, false);
-}
+		}
 
 // virtual
 void LLVOAvatar::removeMissingBakedTextures()
-{	
+			{
 }
 
 //virtual
diff --git a/indra/newview/llvoavatar.h b/indra/newview/llvoavatar.h
index 85f6f25009644fd924decf48af9f1fcdc279dcfe..b05eed344b60ef3877de0f6719f4240bfc349e33 100755
--- a/indra/newview/llvoavatar.h
+++ b/indra/newview/llvoavatar.h
@@ -128,15 +128,15 @@ class LLVOAvatar :
 public:
 	/*virtual*/ void			updateGL();
 	/*virtual*/ LLVOAvatar*		asAvatar();
-	virtual U32    	 	 		processUpdateMessage(LLMessageSystem *mesgsys,
+	virtual U32    	 	 	processUpdateMessage(LLMessageSystem *mesgsys,
 													 void **user_data,
 													 U32 block_num,
 													 const EObjectUpdateType update_type,
 													 LLDataPacker *dp);
-	virtual void   	 	 		idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
+	virtual void   	 	 	idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
 	/*virtual*/ BOOL   	 	 	updateLOD();
-	BOOL  	 	 	 	 		updateJointLODs();
-	void						updateLODRiggedAttachments( void );
+	BOOL  	 	 	 	 	updateJointLODs();
+	void					updateLODRiggedAttachments( void );
 	/*virtual*/ BOOL   	 	 	isActive() const; // Whether this object needs to do an idleUpdate.
 	S32 						totalTextureMemForUUIDS(std::set<LLUUID>& ids);
 	bool 						allTexturesCompletelyDownloaded(std::set<LLUUID>& ids) const;
@@ -162,22 +162,22 @@ class LLVOAvatar :
 	/*virtual*/ void   	 	 	updateRegion(LLViewerRegion *regionp);
 	/*virtual*/ void   	 	 	updateSpatialExtents(LLVector4a& newMin, LLVector4a &newMax);
 	/*virtual*/ void   	 	 	getSpatialExtents(LLVector4a& newMin, LLVector4a& newMax);
-	/*virtual*/ BOOL   	 	 	lineSegmentIntersect(const LLVector3& start, const LLVector3& end,
+	/*virtual*/ BOOL   	 	 	lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end,
 												 S32 face = -1,                    // which face to check, -1 = ALL_SIDES
 												 BOOL pick_transparent = FALSE,
 												 S32* face_hit = NULL,             // which face was hit
-												 LLVector3* intersection = NULL,   // return the intersection point
+												 LLVector4a* intersection = NULL,   // return the intersection point
 												 LLVector2* tex_coord = NULL,      // return the texture coordinates of the intersection point
-												 LLVector3* normal = NULL,         // return the surface normal at the intersection point
-												 LLVector3* bi_normal = NULL);     // return the surface bi-normal at the intersection point
-	LLViewerObject*	lineSegmentIntersectRiggedAttachments(const LLVector3& start, const LLVector3& end,
+												 LLVector4a* normal = NULL,         // return the surface normal at the intersection point
+												 LLVector4a* tangent = NULL);     // return the surface tangent at the intersection point
+	LLViewerObject*	lineSegmentIntersectRiggedAttachments(const LLVector4a& start, const LLVector4a& end,
 												 S32 face = -1,                    // which face to check, -1 = ALL_SIDES
 												 BOOL pick_transparent = FALSE,
 												 S32* face_hit = NULL,             // which face was hit
-												 LLVector3* intersection = NULL,   // return the intersection point
+												 LLVector4a* intersection = NULL,   // return the intersection point
 												 LLVector2* tex_coord = NULL,      // return the texture coordinates of the intersection point
-												 LLVector3* normal = NULL,         // return the surface normal at the intersection point
-												 LLVector3* bi_normal = NULL);     // return the surface bi-normal at the intersection point
+												 LLVector4a* normal = NULL,         // return the surface normal at the intersection point
+												 LLVector4a* tangent = NULL);     // return the surface tangent at the intersection point
 
 	//--------------------------------------------------------------------
 	// LLCharacter interface and related
diff --git a/indra/newview/llvoavatarself.cpp b/indra/newview/llvoavatarself.cpp
index d54eb5f0400c6f812f23cb1f484e1051de25cdc4..15628d5ab2a85e66e06b6002a3edfe6a0d61639f 100755
--- a/indra/newview/llvoavatarself.cpp
+++ b/indra/newview/llvoavatarself.cpp
@@ -602,7 +602,7 @@ LLVOAvatarSelf::~LLVOAvatarSelf()
  **                                                                             **
  *********************************************************************************/
 
-// virtual
+//virtual
 BOOL LLVOAvatarSelf::updateCharacter(LLAgent &agent)
 {
 	// update screen joint size
@@ -866,10 +866,10 @@ void LLVOAvatarSelf::removeMissingBakedTextures()
 		updateMeshTextures();
 		if (getRegion() && !getRegion()->getCentralBakeVersion())
 		{
-			requestLayerSetUploads();
-		}
+		requestLayerSetUploads();
 	}
 }
+}
 
 //virtual
 void LLVOAvatarSelf::updateRegion(LLViewerRegion *regionp)
@@ -1310,7 +1310,7 @@ void LLVOAvatarSelf::localTextureLoaded(BOOL success, LLViewerFetchedTexture *sr
 			discard_level < local_tex_obj->getDiscard())
 		{
 			local_tex_obj->setDiscard(discard_level);
-			requestLayerSetUpdate(index);
+				requestLayerSetUpdate(index);
 			if (isEditingAppearance())
 			{
 				LLVisualParamHint::requestHintUpdates();
@@ -1799,11 +1799,11 @@ void LLVOAvatarSelf::setLocalTexture(ETextureIndex type, LLViewerTexture* src_te
 					{
 						requestLayerSetUpdate(type);
 						if (isEditingAppearance())
-						{
-							LLVisualParamHint::requestHintUpdates();
-						}
+					{
+						LLVisualParamHint::requestHintUpdates();
 					}
 				}
+				}
 				else
 				{					
 					tex->setLoadedCallback(onLocalTextureLoaded, desired_discard, TRUE, FALSE, new LLAvatarTexData(getID(), type), NULL);
@@ -2580,25 +2580,25 @@ void LLVOAvatarSelf::addLocalTextureStats( ETextureIndex type, LLViewerFetchedTe
 	//if (!covered_by_baked)
 	{
 		if (imagep->getID() != IMG_DEFAULT_AVATAR)
-		{
+	{
 			imagep->setNoDelete();
 			if (imagep->getDiscardLevel() != 0)
-			{
-				F32 desired_pixels;
-				desired_pixels = llmin(mPixelArea, (F32)getTexImageArea());
-				
-				imagep->setBoostLevel(getAvatarBoostLevel());
+		{
+			F32 desired_pixels;
+			desired_pixels = llmin(mPixelArea, (F32)getTexImageArea());
+
+			imagep->setBoostLevel(getAvatarBoostLevel());
 				imagep->setAdditionalDecodePriority(SELF_ADDITIONAL_PRI) ;
-				imagep->resetTextureStats();
-				imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL);
-				imagep->addTextureStats( desired_pixels / texel_area_ratio );
-				imagep->forceUpdateBindStats() ;
-				if (imagep->getDiscardLevel() < 0)
-				{
-					mHasGrey = TRUE; // for statistics gathering
-				}
+			imagep->resetTextureStats();
+			imagep->setMaxVirtualSizeResetInterval(MAX_TEXTURE_VIRTURE_SIZE_RESET_INTERVAL);
+			imagep->addTextureStats( desired_pixels / texel_area_ratio );
+			imagep->forceUpdateBindStats() ;
+			if (imagep->getDiscardLevel() < 0)
+			{
+				mHasGrey = TRUE; // for statistics gathering
 			}
 		}
+		}
 		else
 		{
 			// texture asset is missing
@@ -2921,17 +2921,17 @@ void LLVOAvatarSelf::requestLayerSetUpdate(ETextureIndex index )
 
 LLViewerTexLayerSet* LLVOAvatarSelf::getLayerSet(ETextureIndex index) const
 {
-       /* switch(index)
-               case TEX_HEAD_BAKED:
-               case TEX_HEAD_BODYPAINT:
-                       return mHeadLayerSet; */
+	/* switch(index)
+		case TEX_HEAD_BAKED:
+		case TEX_HEAD_BODYPAINT:
+			return mHeadLayerSet; */
        const LLAvatarAppearanceDictionary::TextureEntry *texture_dict = LLAvatarAppearanceDictionary::getInstance()->getTexture(index);
-       if (texture_dict->mIsUsedByBakedTexture)
-       {
-               const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
+	if (texture_dict->mIsUsedByBakedTexture)
+	{
+		const EBakedTextureIndex baked_index = texture_dict->mBakedTextureIndex;
                return getLayerSet(baked_index);
-       }
-       return NULL;
+	}
+	return NULL;
 }
 
 LLViewerTexLayerSet* LLVOAvatarSelf::getLayerSet(EBakedTextureIndex baked_index) const
@@ -2959,7 +2959,7 @@ void LLVOAvatarSelf::onCustomizeStart(bool disable_camera_switch)
 		gAgentAvatarp->mUseLocalAppearance = true;
 
 		if (gSavedSettings.getBOOL("AppearanceCameraMovement") && !disable_camera_switch)
-		{
+{
 			gAgentCamera.changeCameraToCustomizeAvatar();
 		}
 
diff --git a/indra/newview/llvograss.cpp b/indra/newview/llvograss.cpp
index 6a25b765cf86a4c43492a086481a1d817040aea0..cab5c4bc1dfb05512b0e1e21ed2154f437e686ca 100755
--- a/indra/newview/llvograss.cpp
+++ b/indra/newview/llvograss.cpp
@@ -764,8 +764,8 @@ void LLVOGrass::updateDrawable(BOOL force_damped)
 }
 
 // virtual 
-BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face, BOOL pick_transparent, S32 *face_hitp,
-									  LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
+BOOL LLVOGrass::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, S32 *face_hitp,
+									  LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent)
 	
 {
 	BOOL ret = FALSE;
@@ -776,7 +776,8 @@ BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& en
 		return FALSE;
 	}
 
-	LLVector3 dir = end-start;
+	LLVector4a dir;
+	dir.setSub(end, start);
 
 	mPatch = mRegionp->getLand().resolvePatchRegion(getPositionRegion());
 	
@@ -844,23 +845,31 @@ BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& en
 
 		U32 idx0 = 0,idx1 = 0,idx2 = 0;
 
-		if (LLTriangleRayIntersect(v[0], v[1], v[2], start, dir, a, b, t, FALSE))
+		LLVector4a v0a,v1a,v2a,v3a;
+
+		v0a.load3(v[0].mV);
+		v1a.load3(v[1].mV);
+		v2a.load3(v[2].mV);
+		v3a.load3(v[3].mV);
+
+		
+		if (LLTriangleRayIntersect(v0a, v1a, v2a, start, dir, a, b, t))
 		{
 			hit = TRUE;
 			idx0 = 0; idx1 = 1; idx2 = 2;
 		}
-		else if (LLTriangleRayIntersect(v[1], v[3], v[2], start, dir, a, b, t, FALSE))
+		else if (LLTriangleRayIntersect(v1a, v3a, v2a, start, dir, a, b, t))
 		{
 			hit = TRUE;
 			idx0 = 1; idx1 = 3; idx2 = 2;
 		}
-		else if (LLTriangleRayIntersect(v[2], v[1], v[0], start, dir, a, b, t, FALSE))
+		else if (LLTriangleRayIntersect(v2a, v1a, v0a, start, dir, a, b, t))
 		{
 			normal1 = -normal1;
 			hit = TRUE;
 			idx0 = 2; idx1 = 1; idx2 = 0;
 		}
-		else if (LLTriangleRayIntersect(v[2], v[3], v[1], start, dir, a, b, t, FALSE))
+		else if (LLTriangleRayIntersect(v2a, v3a, v1a, start, dir, a, b, t))
 		{
 			normal1 = -normal1;
 			hit = TRUE;
@@ -883,7 +892,8 @@ BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& en
 					closest_t = t;
 					if (intersection != NULL)
 					{
-						*intersection = start+dir*closest_t;
+						dir.mul(closest_t);
+						intersection->setAdd(start, dir);
 					}
 
 					if (tex_coord != NULL)
@@ -893,7 +903,7 @@ BOOL LLVOGrass::lineSegmentIntersect(const LLVector3& start, const LLVector3& en
 
 					if (normal != NULL)
 					{
-						*normal    = normal1;
+						normal->load3(normal1.mV);
 					}
 					ret = TRUE;
 				}
diff --git a/indra/newview/llvograss.h b/indra/newview/llvograss.h
index b9835b8802a77f5ff8420e8ddb5452e57a8553bd..122806766de78505e5164f00446dd3fb6118bc08 100755
--- a/indra/newview/llvograss.h
+++ b/indra/newview/llvograss.h
@@ -75,14 +75,14 @@ class LLVOGrass : public LLAlphaObject
 	/*virtual*/ BOOL    isActive() const; // Whether this object needs to do an idleUpdate.
 	/*virtual*/ void idleUpdate(LLAgent &agent, LLWorld &world, const F64 &time);
 
-	/*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, 
+	/*virtual*/ BOOL lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, 
 										  S32 face = -1,                        // which face to check, -1 = ALL_SIDES
 										  BOOL pick_transparent = FALSE,
 										  S32* face_hit = NULL,                 // which face was hit
-										  LLVector3* intersection = NULL,       // return the intersection point
+										  LLVector4a* intersection = NULL,       // return the intersection point
 										  LLVector2* tex_coord = NULL,          // return the texture coordinates of the intersection point
-										  LLVector3* normal = NULL,             // return the surface normal at the intersection point
-										  LLVector3* bi_normal = NULL           // return the surface bi-normal at the intersection point
+										  LLVector4a* normal = NULL,             // return the surface normal at the intersection point
+										  LLVector4a* tangent = NULL           // return the surface tangent at the intersection point
 		);
 
 	static S32 sMaxGrassSpecies;
diff --git a/indra/newview/llvopartgroup.cpp b/indra/newview/llvopartgroup.cpp
index 0b34bbb90f6cb44429a6cc727490c388c5de1799..43a5ddba425c70bbdee7eb2182576888e3c15a71 100755
--- a/indra/newview/llvopartgroup.cpp
+++ b/indra/newview/llvopartgroup.cpp
@@ -65,7 +65,9 @@ void LLVOPartGroup::initClass()
 //static
 void LLVOPartGroup::restoreGL()
 {
-	sVB = new LLVertexBuffer(VERTEX_DATA_MASK, GL_STREAM_DRAW_ARB);
+
+	//TODO: optimize out binormal mask here.  Specular and normal coords as well.
+	sVB = new LLVertexBuffer(VERTEX_DATA_MASK | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2, GL_STREAM_DRAW_ARB);
 	U32 count = LL_MAX_PARTICLE_COUNT;
 	sVB->allocateBuffer(count*4, count*6, true);
 
@@ -410,6 +412,7 @@ void LLVOPartGroup::getGeometry(S32 idx,
 
 	right.setCross3(at, up);
 	right.normalize3fast();
+
 	up.setCross3(right, at);
 	up.normalize3fast();
 
diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp
index de15f0ef43f68cfeabc30996e9a4ac14f689bd77..9a5c5831ca9d1e1358c709ea89fcdf71f3ec14ef 100755
--- a/indra/newview/llvosurfacepatch.cpp
+++ b/indra/newview/llvosurfacepatch.cpp
@@ -97,10 +97,10 @@ class LLVertexBufferTerrain : public LLVertexBuffer
 			glTexCoordPointer(2,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TEXCOORD1], (void*)(base + mOffsets[TYPE_TEXCOORD1]));
 			glClientActiveTextureARB(GL_TEXTURE0_ARB);
 		}
-		if (data_mask & MAP_BINORMAL)
+		if (data_mask & MAP_TANGENT)
 		{
 			glClientActiveTextureARB(GL_TEXTURE2_ARB);
-			glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_BINORMAL], (void*)(base + mOffsets[TYPE_BINORMAL]));
+			glTexCoordPointer(3,GL_FLOAT, LLVertexBuffer::sTypeSize[TYPE_TANGENT], (void*)(base + mOffsets[TYPE_TANGENT]));
 			glClientActiveTextureARB(GL_TEXTURE0_ARB);
 		}
 		if (data_mask & MAP_TEXCOORD0)
@@ -936,8 +936,8 @@ void LLVOSurfacePatch::getGeomSizesEast(const S32 stride, const S32 east_stride,
 	}
 }
 
-BOOL LLVOSurfacePatch::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face, BOOL pick_transparent, S32 *face_hitp,
-									  LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
+BOOL LLVOSurfacePatch::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, S32 *face_hitp,
+									  LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent)
 	
 {
 
@@ -946,7 +946,9 @@ BOOL LLVOSurfacePatch::lineSegmentIntersect(const LLVector3& start, const LLVect
 		return FALSE;
 	}
 
-	LLVector3 delta = end-start;
+	LLVector4a da;
+	da.setSub(end, start);
+	LLVector3 delta(da.getF32ptr());
 		
 	LLVector3 pdelta = delta;
 	pdelta.mV[2] = 0;
@@ -955,7 +957,9 @@ BOOL LLVOSurfacePatch::lineSegmentIntersect(const LLVector3& start, const LLVect
 	
 	F32 tdelta = 1.f/plength;
 
-	LLVector3 origin = start - mRegionp->getOriginAgent();
+	LLVector3 v_start(start.getF32ptr());
+
+	LLVector3 origin = v_start - mRegionp->getOriginAgent();
 
 	if (mRegionp->getLandHeightRegion(origin) > origin.mV[2])
 	{
@@ -1010,12 +1014,12 @@ BOOL LLVOSurfacePatch::lineSegmentIntersect(const LLVector3& start, const LLVect
 					{
 						sample.mV[2] = mRegionp->getLandHeightRegion(sample);
 					}
-					*intersection = sample + mRegionp->getOriginAgent();
+					intersection->load3((sample + mRegionp->getOriginAgent()).mV);
 				}
 
 				if (normal)
 				{
-					*normal = mRegionp->getLand().resolveNormalGlobal(mRegionp->getPosGlobalFromRegion(sample));
+					normal->load3((mRegionp->getLand().resolveNormalGlobal(mRegionp->getPosGlobalFromRegion(sample))).mV);
 				}
 
 				return TRUE;
diff --git a/indra/newview/llvosurfacepatch.h b/indra/newview/llvosurfacepatch.h
index a15878368e4c515ede7f3ed1c90f9a1c3b2680cd..7b53219be85f085e353611524ccec7c04a9a18cb 100755
--- a/indra/newview/llvosurfacepatch.h
+++ b/indra/newview/llvosurfacepatch.h
@@ -79,14 +79,14 @@ class LLVOSurfacePatch : public LLStaticViewerObject
 	void dirtyPatch();
 	void dirtyGeom();
 
-	/*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, 
+	/*virtual*/ BOOL lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, 
 										  S32 face = -1,                        // which face to check, -1 = ALL_SIDES
 										  BOOL pick_transparent = FALSE,
 										  S32* face_hit = NULL,                 // which face was hit
-										  LLVector3* intersection = NULL,       // return the intersection point
+										  LLVector4a* intersection = NULL,       // return the intersection point
 										  LLVector2* tex_coord = NULL,          // return the texture coordinates of the intersection point
-										  LLVector3* normal = NULL,             // return the surface normal at the intersection point
-										  LLVector3* bi_normal = NULL           // return the surface bi-normal at the intersection point
+										  LLVector4a* normal = NULL,             // return the surface normal at the intersection point
+										  LLVector4a* tangent = NULL           // return the surface tangent at the intersection point
 		);
 
 	BOOL			mDirtiedPatch;
diff --git a/indra/newview/llvotree.cpp b/indra/newview/llvotree.cpp
index 145a0380d6891d611e7e3494251a627fce71c76d..cd12cd95520e70a1e3443bdffeaae2a1bfbc7217 100755
--- a/indra/newview/llvotree.cpp
+++ b/indra/newview/llvotree.cpp
@@ -1085,132 +1085,6 @@ void LLVOTree::calcNumVerts(U32& vert_count, U32& index_count, S32 trunk_LOD, S3
 	}
 }
 
-U32 LLVOTree::drawBranchPipeline(LLMatrix4& matrix, U16* indicesp, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth,  F32 scale, F32 twist, F32 droop,  F32 branches, F32 alpha)
-{
-	U32 ret = 0;
-	//
-	//  Draws a tree by recursing, drawing branches and then a 'leaf' texture.
-	//  If stop_level = -1, simply draws the whole tree as a billboarded texture
-	//
-	
-	static F32 constant_twist;
-	static F32 width = 0;
-
-	//F32 length = ((scale == 1.f)? mTrunkLength:mBranchLength);
-	//F32 aspect = ((scale == 1.f)? mTrunkAspect:mBranchAspect);
-	F32 length = ((trunk_depth || (scale == 1.f))? mTrunkLength:mBranchLength);
-	F32 aspect = ((trunk_depth || (scale == 1.f))? mTrunkAspect:mBranchAspect);
-	
-	constant_twist = 360.f/branches;
-
-	if (!LLPipeline::sReflectionRender && stop_level >= 0)
-	{
-		//
-		//  Draw the tree using recursion
-		//
-		if (depth > stop_level)
-		{
-			{
-				llassert(sLODIndexCount[trunk_LOD] > 0);
-				width = scale * length * aspect;
-				LLMatrix4 scale_mat;
-				scale_mat.mMatrix[0][0] = width;
-				scale_mat.mMatrix[1][1] = width;
-				scale_mat.mMatrix[2][2] = scale*length;
-				scale_mat *= matrix;
-
-				gGL.loadMatrix((F32*) scale_mat.mMatrix);
-				gGL.syncMatrices();
- 				glDrawElements(GL_TRIANGLES, sLODIndexCount[trunk_LOD], GL_UNSIGNED_SHORT, indicesp + sLODIndexOffset[trunk_LOD]);
-				gPipeline.addTrianglesDrawn(LEAF_INDICES);
-				stop_glerror();
-				ret += sLODIndexCount[trunk_LOD];
-			}
-			
-			// Recurse to create more branches
-			for (S32 i=0; i < (S32)branches; i++) 
-			{
-				LLMatrix4 trans_mat;
-				trans_mat.setTranslation(0,0,scale*length);
-				trans_mat *= matrix;
-
-				LLQuaternion rot = 
-					LLQuaternion(20.f*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f)) *
-					LLQuaternion(droop*DEG_TO_RAD, LLVector4(0.f, 1.f, 0.f)) *
-					LLQuaternion(((constant_twist + ((i%2==0)?twist:-twist))*i)*DEG_TO_RAD, LLVector4(0.f, 0.f, 1.f));
-				
-				LLMatrix4 rot_mat(rot);
-				rot_mat *= trans_mat;
-
-				ret += drawBranchPipeline(rot_mat, indicesp, trunk_LOD, stop_level, depth - 1, 0, scale*mScaleStep, twist, droop, branches, alpha);
-			}
-			//  Recurse to continue trunk
-			if (trunk_depth)
-			{
-				LLMatrix4 trans_mat;
-				trans_mat.setTranslation(0,0,scale*length);
-				trans_mat *= matrix;
-
-				LLMatrix4 rot_mat(70.5f*DEG_TO_RAD, LLVector4(0,0,1));
-				rot_mat *= trans_mat; // rotate a bit around Z when ascending 
-				ret += drawBranchPipeline(rot_mat, indicesp, trunk_LOD, stop_level, depth, trunk_depth-1, scale*mScaleStep, twist, droop, branches, alpha);
-			}
-		}
-		else
-		{
-			//
-			//  Draw leaves as two 90 deg crossed quads with leaf textures
-			//
-			{
-				LLMatrix4 scale_mat;
-				scale_mat.mMatrix[0][0] = 
-					scale_mat.mMatrix[1][1] =
-					scale_mat.mMatrix[2][2] = scale*mLeafScale;
-
-				scale_mat *= matrix;
-
-			
-				gGL.loadMatrix((F32*) scale_mat.mMatrix);
-				gGL.syncMatrices();
-				glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_SHORT, indicesp);
-				gPipeline.addTrianglesDrawn(LEAF_INDICES);							
-				stop_glerror();
-				ret += LEAF_INDICES;
-			}
-		}
-	}
-	else
-	{
-		//
-		//  Draw the tree as a single billboard texture 
-		//
-
-		LLMatrix4 scale_mat;
-		scale_mat.mMatrix[0][0] = 
-			scale_mat.mMatrix[1][1] =
-			scale_mat.mMatrix[2][2] = mBillboardScale*mBillboardRatio;
-
-		scale_mat *= matrix;
-	
-		gGL.matrixMode(LLRender::MM_TEXTURE);
-		gGL.translatef(0.0, -0.5, 0.0);
-		gGL.matrixMode(LLRender::MM_MODELVIEW);
-					
-		gGL.loadMatrix((F32*) scale_mat.mMatrix);
-		gGL.syncMatrices();
-		glDrawElements(GL_TRIANGLES, LEAF_INDICES, GL_UNSIGNED_SHORT, indicesp);
-		gPipeline.addTrianglesDrawn(LEAF_INDICES);
-		stop_glerror();
-		ret += LEAF_INDICES;
-
-		gGL.matrixMode(LLRender::MM_TEXTURE);
-		gGL.loadIdentity();
-		gGL.matrixMode(LLRender::MM_MODELVIEW);
-	}
-
-	return ret;
-}
-
 void LLVOTree::updateRadius()
 {
 	if (mDrawable.isNull())
@@ -1238,8 +1112,8 @@ void LLVOTree::updateSpatialExtents(LLVector4a& newMin, LLVector4a& newMax)
 	mDrawable->setPositionGroup(pos);
 }
 
-BOOL LLVOTree::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face, BOOL pick_transparent, S32 *face_hitp,
-									  LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
+BOOL LLVOTree::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, S32 *face_hitp,
+									  LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent)
 	
 {
 
@@ -1268,16 +1142,19 @@ BOOL LLVOTree::lineSegmentIntersect(const LLVector3& start, const LLVector3& end
 
 	LLVector3 pos, norm;
 		
-	if (linesegment_tetrahedron(start, end, center, size, quat, pos, norm))
+	LLVector3 start3(start.getF32ptr());
+	LLVector3 end3(end.getF32ptr());
+
+	if (linesegment_tetrahedron(start3, end3, center, size, quat, pos, norm))
 	{
 		if (intersection)
 		{
-			*intersection = pos;
+			intersection->load3(pos.mV);
 		}
 
 		if (normal)
 		{
-			*normal = norm;
+			normal->load3(norm.mV);
 		}
 		return TRUE;
 	}
diff --git a/indra/newview/llvotree.h b/indra/newview/llvotree.h
index 52debc85abcc6ce86317df93e3f12b8ed62d188b..2ecb0303a1bbd082f6df716abfe1dc3d64301877 100755
--- a/indra/newview/llvotree.h
+++ b/indra/newview/llvotree.h
@@ -104,19 +104,16 @@ class LLVOTree : public LLViewerObject
 								 F32 twist, 
 								 F32 droop,  
 								 F32 branches, 
-								 F32 alpha);
+								 F32 alpha); 
 
-	U32 drawBranchPipeline(LLMatrix4& matrix, U16* indicesp, S32 trunk_LOD, S32 stop_level, U16 depth, U16 trunk_depth,  F32 scale, F32 twist, F32 droop,  F32 branches, F32 alpha);
- 
-
-	 /*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, 
+	 /*virtual*/ BOOL lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, 
 										  S32 face = -1,                        // which face to check, -1 = ALL_SIDES
 										  BOOL pick_transparent = FALSE,
 										  S32* face_hit = NULL,                 // which face was hit
-										  LLVector3* intersection = NULL,       // return the intersection point
+										  LLVector4a* intersection = NULL,       // return the intersection point
 										  LLVector2* tex_coord = NULL,          // return the texture coordinates of the intersection point
-										  LLVector3* normal = NULL,             // return the surface normal at the intersection point
-										  LLVector3* bi_normal = NULL           // return the surface bi-normal at the intersection point
+										  LLVector4a* normal = NULL,             // return the surface normal at the intersection point
+										  LLVector4a* tangent = NULL           // return the surface tangent at the intersection point
 		);
 
 	static S32 sMaxTreeSpecies;
diff --git a/indra/newview/llvovolume.cpp b/indra/newview/llvovolume.cpp
index 8730ef66bbaa503fcbbc7ed00efac0bf5edbed03..3be1f523529c78adbe6f42692a8a044fe53e4c93 100755
--- a/indra/newview/llvovolume.cpp
+++ b/indra/newview/llvovolume.cpp
@@ -36,6 +36,7 @@
 #include "lldir.h"
 #include "llflexibleobject.h"
 #include "llfloatertools.h"
+#include "llmaterialid.h"
 #include "llmaterialtable.h"
 #include "llprimitive.h"
 #include "llvolume.h"
@@ -76,6 +77,7 @@
 #include "llviewershadermgr.h"
 #include "llvoavatar.h"
 #include "llvocache.h"
+#include "llmaterialmgr.h"
 
 const S32 MIN_QUIET_FRAMES_COALESCE = 30;
 const F32 FORCE_SIMPLE_RENDER_AREA = 512.f;
@@ -554,37 +556,9 @@ void LLVOVolume::animateTextures()
 				tex_mat.setIdentity();
 				LLVector3 trans ;
 
-				if(facep->isAtlasInUse())
-				{
-					//
-					//if use atlas for animated texture
-					//apply the following transform to the animation matrix.
-					//
-
-					F32 tcoord_xoffset = 0.f ;
-					F32 tcoord_yoffset = 0.f ;
-					F32 tcoord_xscale = 1.f ;
-					F32 tcoord_yscale = 1.f ;			
-					if(facep->isAtlasInUse())
-					{
-						const LLVector2* tmp = facep->getTexCoordOffset() ;
-						tcoord_xoffset = tmp->mV[0] ; 
-						tcoord_yoffset = tmp->mV[1] ;
-
-						tmp = facep->getTexCoordScale() ;
-						tcoord_xscale = tmp->mV[0] ; 
-						tcoord_yscale = tmp->mV[1] ;	
-					}
-					trans.set(LLVector3(tcoord_xoffset + tcoord_xscale * (off_s+0.5f), tcoord_yoffset + tcoord_yscale * (off_t+0.5f), 0.f));
-
-					tex_mat.translate(LLVector3(-(tcoord_xoffset + tcoord_xscale * 0.5f), -(tcoord_yoffset + tcoord_yscale * 0.5f), 0.f));
-				}
-				else	//non atlas
-				{
-					trans.set(LLVector3(off_s+0.5f, off_t+0.5f, 0.f));			
-					tex_mat.translate(LLVector3(-0.5f, -0.5f, 0.f));
-				}
-
+				trans.set(LLVector3(off_s+0.5f, off_t+0.5f, 0.f));			
+				tex_mat.translate(LLVector3(-0.5f, -0.5f, 0.f));
+				
 				LLVector3 scale(scale_s, scale_t, 1.f);			
 				LLQuaternion quat;
 				quat.setQuat(rot, 0, 0, -1.f);
@@ -918,6 +892,12 @@ LLFace* LLVOVolume::addFace(S32 f)
 {
 	const LLTextureEntry* te = getTE(f);
 	LLViewerTexture* imagep = getTEImage(f);
+	if (te->getMaterialParams().notNull())
+	{
+		LLViewerTexture* normalp = getTENormalMap(f);
+		LLViewerTexture* specularp = getTESpecularMap(f);
+		return mDrawable->addFace(te, imagep, normalp, specularp);
+	}
 	return mDrawable->addFace(te, imagep);
 }
 
@@ -1066,7 +1046,7 @@ BOOL LLVOVolume::setVolume(const LLVolumeParams &params_in, const S32 detail, bo
 				{ //already cached
 					break;
 				}
-				volume->genBinormals(i);
+				volume->genTangents(i);
 				LLFace::cacheFaceInVRAM(face);
 			}
 		}
@@ -1415,6 +1395,11 @@ void LLVOVolume::regenFaces()
 
 		facep->setTEOffset(i);
 		facep->setTexture(getTEImage(i));
+		if (facep->getTextureEntry()->getMaterialParams().notNull())
+		{
+			facep->setNormalMap(getTENormalMap(i));
+			facep->setSpecularMap(getTESpecularMap(i));
+		}
 		facep->setViewerObject(this);
 		
 		// If the face had media on it, this will have broken the link between the LLViewerMediaTexture and the face.
@@ -1876,7 +1861,7 @@ S32 LLVOVolume::setTEColor(const U8 te, const LLColor4& color)
 	const LLTextureEntry *tep = getTE(te);
 	if (!tep)
 	{
-		llwarns << "No texture entry for te " << (S32)te << ", object " << mID << llendl;
+		LL_WARNS("MaterialTEs") << "No texture entry for te " << (S32)te << ", object " << mID << LL_ENDL;
 	}
 	else if (color != tep->getColor())
 	{
@@ -1988,6 +1973,62 @@ S32 LLVOVolume::setTEGlow(const U8 te, const F32 glow)
 	return  res;
 }
 
+void LLVOVolume::setTEMaterialParamsCallbackTE(const LLUUID& objectID, const LLMaterialID &pMaterialID, const LLMaterialPtr pMaterialParams, U32 te)
+{
+	LLVOVolume* pVol = (LLVOVolume*)gObjectList.findObject(objectID);
+	if (pVol)
+	{
+		LL_DEBUGS("MaterialTEs") << "materialid " << pMaterialID.asString() << " to TE " << te << LL_ENDL;
+		if (te >= pVol->getNumTEs())
+			return;
+
+		LLTextureEntry* texture_entry = pVol->getTE(te);
+		if (texture_entry && (texture_entry->getMaterialID() == pMaterialID))
+		{
+			pVol->setTEMaterialParams(te, pMaterialParams);
+		}
+	}
+}
+
+S32 LLVOVolume::setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID)
+{
+	S32 res = LLViewerObject::setTEMaterialID(te, pMaterialID);
+	LL_DEBUGS("MaterialTEs") << "te "<< (S32)te << " materialid " << pMaterialID.asString() << " res " << res
+								<< ( LLSelectMgr::getInstance()->getSelection()->contains(const_cast<LLVOVolume*>(this), te) ? " selected" : " not selected" )
+								<< LL_ENDL;
+		
+	LL_DEBUGS("MaterialTEs") << " " << pMaterialID.asString() << LL_ENDL;
+	if (res)
+	{
+		LLMaterialMgr::instance().getTE(getRegion()->getRegionID(), pMaterialID, te, boost::bind(&LLVOVolume::setTEMaterialParamsCallbackTE, getID(), _1, _2, _3));
+
+		setChanged(ALL_CHANGED);
+		if (!mDrawable.isNull())
+		{
+			gPipeline.markTextured(mDrawable);
+			gPipeline.markRebuild(mDrawable,LLDrawable::REBUILD_ALL);
+		}
+		mFaceMappingChanged = TRUE;
+	}
+	return res;
+}
+
+S32 LLVOVolume::setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams)
+{
+	S32 res = LLViewerObject::setTEMaterialParams(te, pMaterialParams);
+	LL_DEBUGS("MaterialTEs") << "te " << (S32)te << " material " << ((pMaterialParams) ? pMaterialParams->asLLSD() : LLSD("null")) << " res " << res
+							 << ( LLSelectMgr::getInstance()->getSelection()->contains(const_cast<LLVOVolume*>(this), te) ? " selected" : " not selected" )
+							 << LL_ENDL;
+	setChanged(ALL_CHANGED);
+	if (!mDrawable.isNull())
+	{
+		gPipeline.markTextured(mDrawable);
+		gPipeline.markRebuild(mDrawable,LLDrawable::REBUILD_ALL);
+	}
+	mFaceMappingChanged = TRUE;
+	return TEM_CHANGE_TEXTURE;
+}
+
 S32 LLVOVolume::setTEScale(const U8 te, const F32 s, const F32 t)
 {
 	S32 res = LLViewerObject::setTEScale(te, s, t);
@@ -3476,7 +3517,12 @@ F32 LLVOVolume::getBinRadius()
 	}
 	else if (mDrawable->isStatic())
 	{
-		radius = llmax((S32) mDrawable->getRadius(), 1)*size_factor;
+		F32 szf = size_factor;
+
+		radius = llmax(mDrawable->getRadius(), szf);
+		
+		radius = powf(radius, 1.f+szf/radius);
+
 		radius *= 1.f + mDrawable->mDistanceWRTCamera * distance_factor[1];
 		radius += mDrawable->mDistanceWRTCamera * distance_factor[0];
 	}
@@ -3573,8 +3619,8 @@ LLVector3 LLVOVolume::volumeDirectionToAgent(const LLVector3& dir) const
 }
 
 
-BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& end, S32 face, BOOL pick_transparent, S32 *face_hitp,
-									  LLVector3* intersection,LLVector2* tex_coord, LLVector3* normal, LLVector3* bi_normal)
+BOOL LLVOVolume::lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, S32 face, BOOL pick_transparent, S32 *face_hitp,
+									  LLVector4a* intersection,LLVector2* tex_coord, LLVector4a* normal, LLVector4a* tangent)
 	
 {
 	if (!mbCanSelect 
@@ -3606,23 +3652,25 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
 	
 	if (volume)
 	{	
-		LLVector3 v_start, v_end, v_dir;
-	
+		LLVector4a local_start = start;
+		LLVector4a local_end = end;
+		
 		if (transform)
 		{
-			v_start = agentPositionToVolume(start);
-			v_end = agentPositionToVolume(end);
-		}
-		else
-		{
-			v_start = start;
-			v_end = end;
-		}
+			LLVector3 v_start(start.getF32ptr());
+			LLVector3 v_end(end.getF32ptr());
 		
-		LLVector3 p;
-		LLVector3 n;
+			v_start = agentPositionToVolume(v_start);
+			v_end = agentPositionToVolume(v_end);
+
+			local_start.load3(v_start.mV);
+			local_end.load3(v_end.mV);
+		}
+				
+		LLVector4a p;
+		LLVector4a n;
 		LLVector2 tc;
-		LLVector3 bn;
+		LLVector4a tn;
 
 		if (intersection != NULL)
 		{
@@ -3639,9 +3687,9 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
 			n = *normal;
 		}
 
-		if (bi_normal != NULL)
+		if (tangent != NULL)
 		{
-			bn = *bi_normal;
+			tn = *tangent;
 		}
 
 		S32 face_hit = -1;
@@ -3667,8 +3715,8 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
 				continue;
 			}
 
-			face_hit = volume->lineSegmentIntersect(v_start, v_end, i,
-													&p, &tc, &n, &bn);
+			face_hit = volume->lineSegmentIntersect(local_start, local_end, i,
+													&p, &tc, &n, &tn);
 			
 			if (face_hit >= 0 && mDrawable->getNumFaces() > face_hit)
 			{
@@ -3677,7 +3725,7 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
 				if (face &&
 					(pick_transparent || !face->getTexture() || !face->getTexture()->hasGLTexture() || face->getTexture()->getMask(face->surfaceToTexture(tc, p, n))))
 				{
-					v_end = p;
+					local_end = p;
 					if (face_hitp != NULL)
 					{
 						*face_hitp = face_hit;
@@ -3687,7 +3735,9 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
 					{
 						if (transform)
 						{
-							*intersection = volumePositionToAgent(p);  // must map back to agent space
+							LLVector3 v_p(p.getF32ptr());
+
+							intersection->load3(volumePositionToAgent(v_p).mV);  // must map back to agent space
 						}
 						else
 						{
@@ -3699,27 +3749,36 @@ BOOL LLVOVolume::lineSegmentIntersect(const LLVector3& start, const LLVector3& e
 					{
 						if (transform)
 						{
-							*normal = volumeDirectionToAgent(n);
+							LLVector3 v_n(n.getF32ptr());
+							normal->load3(volumeDirectionToAgent(v_n).mV);
 						}
 						else
 						{
 							*normal = n;
 						}
-
-						(*normal).normVec();
+						(*normal).normalize3fast();
 					}
 
-					if (bi_normal != NULL)
+					if (tangent != NULL)
 					{
 						if (transform)
 						{
-							*bi_normal = volumeDirectionToAgent(bn);
+							LLVector3 v_tn(tn.getF32ptr());
+
+							LLVector4a trans_tangent;
+							trans_tangent.load3(volumeDirectionToAgent(v_tn).mV);
+
+							LLVector4Logical mask;
+							mask.clear();
+							mask.setElement<3>();
+
+							tangent->setSelectWithMask(mask, tn, trans_tangent);
 						}
 						else
 						{
-							*bi_normal = bn;
+							*tangent = tn;
 						}
-						(*bi_normal).normVec();
+						(*tangent).normalize3fast();
 					}
 
 					if (tex_coord != NULL)
@@ -3976,6 +4035,11 @@ bool can_batch_texture(LLFace* facep)
 		return false;
 	}
 
+	if (facep->getTextureEntry()->getMaterialParams().notNull())
+	{ //materials don't work with texture batching yet
+		return false;
+	}
+
 	if (facep->getTexture() && facep->getTexture()->getPrimaryFormat() == GL_ALPHA)
 	{ //can't batch invisiprims
 		return false;
@@ -3994,7 +4058,11 @@ static LLFastTimer::DeclareTimer FTM_REGISTER_FACE("Register Face");
 void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep, U32 type)
 {
 	LLFastTimer t(FTM_REGISTER_FACE);
-
+	if (type == LLRenderPass::PASS_ALPHA && facep->getTextureEntry()->getMaterialParams().notNull() && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_TANGENT))
+	{
+		LL_WARNS("RenderMaterials") << "Oh no! No binormals for this alpha blended face!" << LL_ENDL;
+	}
+	
 	if (facep->getViewerObject()->isSelected() && LLSelectMgr::getInstance()->mHideSelectedObjects)
 	{
 		return;
@@ -4007,7 +4075,9 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 
 	BOOL fullbright = (type == LLRenderPass::PASS_FULLBRIGHT) ||
 		(type == LLRenderPass::PASS_INVISIBLE) ||
-		(type == LLRenderPass::PASS_ALPHA && facep->isState(LLFace::FULLBRIGHT));
+		(type == LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK) ||
+		(type == LLRenderPass::PASS_ALPHA && facep->isState(LLFace::FULLBRIGHT)) ||
+		(facep->getTextureEntry()->getFullbright());
 	
 	if (!fullbright && type != LLRenderPass::PASS_GLOW && !facep->getVertexBuffer()->hasDataType(LLVertexBuffer::TYPE_NORMAL))
 	{
@@ -4041,16 +4111,39 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 	//drawable->getVObj()->setDebugText(llformat("%d", drawable->isState(LLDrawable::ANIMATED_CHILD)));
 
 	U8 bump = (type == LLRenderPass::PASS_BUMP || type == LLRenderPass::PASS_POST_BUMP) ? facep->getTextureEntry()->getBumpmap() : 0;
-	
+	U8 shiny = facep->getTextureEntry()->getShiny();
+
 	LLViewerTexture* tex = facep->getTexture();
 
 	U8 index = facep->getTextureIndex();
+	
+	LLMaterial* mat = facep->getTextureEntry()->getMaterialParams().get(); 
+	LLMaterialID mat_id = facep->getTextureEntry()->getMaterialID();
 
 	bool batchable = false;
 
+	U32 shader_mask = 0xFFFFFFFF; //no shader
+
+	if (mat)
+	{
+		if (type == LLRenderPass::PASS_ALPHA)
+		{
+			shader_mask = mat->getShaderMask(LLMaterial::DIFFUSE_ALPHA_MODE_BLEND);
+		}
+		else
+		{
+			shader_mask = mat->getShaderMask();
+		}
+	}
+
+
 	if (index < 255 && idx >= 0)
 	{
-		if (index < draw_vec[idx]->mTextureList.size())
+		if (mat || draw_vec[idx]->mMaterial)
+		{ //can't batch textures when materials are present (yet)
+			batchable = false;
+		}
+		else if (index < draw_vec[idx]->mTextureList.size())
 		{
 			if (draw_vec[idx]->mTextureList[index].isNull())
 			{
@@ -4076,16 +4169,20 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		draw_vec[idx]->mEnd - draw_vec[idx]->mStart + facep->getGeomCount() <= (U32) gGLManager.mGLMaxVertexRange &&
 		draw_vec[idx]->mCount + facep->getIndicesCount() <= (U32) gGLManager.mGLMaxIndexRange &&
 #endif
+		draw_vec[idx]->mMaterial == mat &&
+		draw_vec[idx]->mMaterialID == mat_id &&
 		draw_vec[idx]->mFullbright == fullbright &&
-		draw_vec[idx]->mBump == bump &&
+		draw_vec[idx]->mBump  == bump  &&
+		(!mat || (draw_vec[idx]->mShiny == shiny)) && // need to break batches when a material is shared, but legacy settings are different
 		draw_vec[idx]->mTextureMatrix == tex_mat &&
-		draw_vec[idx]->mModelMatrix == model_mat)
+		draw_vec[idx]->mModelMatrix == model_mat &&
+		draw_vec[idx]->mShaderMask == shader_mask)
 	{
 		draw_vec[idx]->mCount += facep->getIndicesCount();
 		draw_vec[idx]->mEnd += facep->getGeomCount();
 		draw_vec[idx]->mVSize = llmax(draw_vec[idx]->mVSize, facep->getVirtualSize());
 
-		if (index >= draw_vec[idx]->mTextureList.size())
+		if (index < 255 && index >= draw_vec[idx]->mTextureList.size())
 		{
 			draw_vec[idx]->mTextureList.resize(index+1);
 			draw_vec[idx]->mTextureList[index] = tex;
@@ -4101,12 +4198,66 @@ void LLVolumeGeometryManager::registerFace(LLSpatialGroup* group, LLFace* facep,
 		U32 offset = facep->getIndicesStart();
 		U32 count = facep->getIndicesCount();
 		LLPointer<LLDrawInfo> draw_info = new LLDrawInfo(start,end,count,offset, tex, 
-			facep->getVertexBuffer(), fullbright, bump); 
+			facep->getVertexBuffer(), fullbright, bump);
 		draw_info->mGroup = group;
 		draw_info->mVSize = facep->getVirtualSize();
 		draw_vec.push_back(draw_info);
 		draw_info->mTextureMatrix = tex_mat;
 		draw_info->mModelMatrix = model_mat;
+		
+		draw_info->mBump  = bump;
+		draw_info->mShiny = shiny;
+
+		float alpha[4] =
+		{
+			0.00f,
+			0.25f,
+			0.5f,
+			0.75f
+		};
+		float spec = alpha[shiny & TEM_SHINY_MASK];
+		LLVector4 specColor(spec, spec, spec, spec);
+		draw_info->mSpecColor = specColor;
+		draw_info->mEnvIntensity = spec;
+		draw_info->mSpecularMap = NULL;
+		draw_info->mMaterial = mat;
+		draw_info->mShaderMask = shader_mask;
+
+		if (mat)
+		{
+				draw_info->mMaterialID = mat_id;
+
+				// We have a material.  Update our draw info accordingly.
+				
+				if (!mat->getSpecularID().isNull())
+				{
+					LLVector4 specColor;
+					specColor.mV[0] = mat->getSpecularLightColor().mV[0] * (1.f / 255.f);
+					specColor.mV[1] = mat->getSpecularLightColor().mV[1] * (1.f / 255.f);
+					specColor.mV[2] = mat->getSpecularLightColor().mV[2] * (1.f / 255.f);
+					specColor.mV[3] = mat->getSpecularLightExponent() * (1.f / 255.f);
+					draw_info->mSpecColor = specColor;
+					draw_info->mEnvIntensity = mat->getEnvironmentIntensity() * (1.f / 255.f);
+					draw_info->mSpecularMap = facep->getViewerObject()->getTESpecularMap(facep->getTEOffset());
+				}
+
+				draw_info->mAlphaMaskCutoff = mat->getAlphaMaskCutoff() * (1.f / 255.f);
+				draw_info->mDiffuseAlphaMode = mat->getDiffuseAlphaMode();
+				draw_info->mNormalMap = facep->getViewerObject()->getTENormalMap(facep->getTEOffset());
+				
+		}
+		else 
+		{
+			if (type == LLRenderPass::PASS_GRASS)
+			{
+				draw_info->mAlphaMaskCutoff = 0.5f;
+			}
+			else
+			{
+				draw_info->mAlphaMaskCutoff = 0.33f;
+			}
+		}
+		
 		if (type == LLRenderPass::PASS_ALPHA)
 		{ //for alpha sorting
 			facep->setDrawInfo(draw_info);
@@ -4223,6 +4374,9 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 
 	std::vector<LLFace*> fullbright_faces;
 	std::vector<LLFace*> bump_faces;
+	std::vector<LLFace*> norm_faces;
+	std::vector<LLFace*> spec_faces;
+	std::vector<LLFace*> normspec_faces;
 	std::vector<LLFace*> simple_faces;
 
 	std::vector<LLFace*> alpha_faces;
@@ -4262,7 +4416,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 			}
 
 			if (vobj->isMesh() &&
-				(vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded() || !gMeshRepo.meshRezEnabled()))
+				((vobj->getVolume() && !vobj->getVolume()->isMeshAssetLoaded()) || !gMeshRepo.meshRezEnabled()))
 			{
 				continue;
 			}
@@ -4389,66 +4543,123 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 						LLViewerTexture* tex = facep->getTexture();
 						U32 type = gPipeline.getPoolTypeFromTE(te, tex);
 
-						if (type == LLDrawPool::POOL_ALPHA)
+
+						if (te->getGlow())
 						{
-							if (te->getColor().mV[3] > 0.f)
-							{
-								if (te->getFullbright())
-								{
-									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
-								}
-								else
-								{
-									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
-								}
+							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW);
+						}
+
+						LLMaterial* mat = te->getMaterialParams().get();
+
+						if (mat && LLPipeline::sRenderDeferred)
+						{
+							U8 alpha_mode = mat->getDiffuseAlphaMode();
+
+							bool is_alpha = type == LLDrawPool::POOL_ALPHA &&
+								(alpha_mode == LLMaterial::DIFFUSE_ALPHA_MODE_BLEND ||
+								te->getColor().mV[3] < 0.999f);
+
+							if (is_alpha)
+							{ //this face needs alpha blending, override alpha mode
+								alpha_mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND;
+							}
+
+							if (!is_alpha || te->getColor().mV[3] > 0.f)  // //only add the face if it will actually be visible
+							{ 
+								U32 mask = mat->getShaderMask(alpha_mode);
+								pool->addRiggedFace(facep, mask);
 							}
 						}
-						else if (te->getShiny())
+						else if (mat)
 						{
-							if (te->getFullbright())
+							bool fullbright = te->getFullbright();
+							bool is_alpha = type == LLDrawPool::POOL_ALPHA;
+							U8 mode = mat->getDiffuseAlphaMode();
+							bool can_be_shiny = mode == LLMaterial::DIFFUSE_ALPHA_MODE_NONE ||
+												mode == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE;
+							
+							if (mode == LLMaterial::DIFFUSE_ALPHA_MODE_MASK && te->getColor().mV[3] >= 0.999f)
 							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY);
+								pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT : LLDrawPoolAvatar::RIGGED_SIMPLE);
 							}
-							else
+							else if (is_alpha || (te->getColor().mV[3] < 0.999f))
 							{
-								if (LLPipeline::sRenderDeferred)
-								{
-									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
-								}
-								else
+								if (te->getColor().mV[3] > 0.f)
 								{
-									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY);
+									pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA : LLDrawPoolAvatar::RIGGED_ALPHA);
 								}
 							}
-						}
-						else
-						{
-							if (te->getFullbright())
+							else if (gPipeline.canUseVertexShaders()
+								&& LLPipeline::sRenderBump 
+								&& te->getShiny() 
+								&& can_be_shiny)
 							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT);
+								pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY : LLDrawPoolAvatar::RIGGED_SHINY);
 							}
 							else
 							{
-								pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
+								pool->addRiggedFace(facep, fullbright ? LLDrawPoolAvatar::RIGGED_FULLBRIGHT : LLDrawPoolAvatar::RIGGED_SIMPLE);
 							}
 						}
-
-						if (te->getGlow())
-						{
-							pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_GLOW);
-						}
-
-						if (LLPipeline::sRenderDeferred)
+						else
 						{
-							if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright())
+							if (type == LLDrawPool::POOL_ALPHA)
 							{
-								if (te->getBumpmap())
+								if (te->getColor().mV[3] > 0.f)
 								{
-									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP);
+									if (te->getFullbright())
+									{
+										pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_ALPHA);
+									}
+									else
+									{
+										pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_ALPHA);
+									}
+								}
+							}
+							else if (te->getShiny())
+							{
+								if (te->getFullbright())
+								{
+									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT_SHINY);
 								}
 								else
 								{
-									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE);
+									if (LLPipeline::sRenderDeferred)
+									{
+										pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
+									}
+									else
+									{
+										pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SHINY);
+									}
+								}
+							}
+							else
+							{
+								if (te->getFullbright())
+								{
+									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_FULLBRIGHT);
+								}
+								else
+								{
+									pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_SIMPLE);
+								}
+							}
+
+						
+							if (LLPipeline::sRenderDeferred)
+							{
+								if (type != LLDrawPool::POOL_ALPHA && !te->getFullbright())
+								{
+									if (te->getBumpmap())
+									{
+										pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_BUMP);
+									}
+									else
+									{
+										pool->addRiggedFace(facep, LLDrawPoolAvatar::RIGGED_DEFERRED_SIMPLE);
+									}
 								}
 							}
 						}
@@ -4558,8 +4769,31 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 						if (gPipeline.canUseWindLightShadersOnObjects()
 							&& LLPipeline::sRenderBump)
 						{
-							if (te->getBumpmap())
-							{ //needs normal + binormal
+							if (LLPipeline::sRenderDeferred && te->getMaterialParams().notNull()  && !te->getMaterialID().isNull())
+							{
+								LLMaterial* mat = te->getMaterialParams().get();
+								if (mat->getNormalID().notNull())
+								{
+									if (mat->getSpecularID().notNull())
+									{ //has normal and specular maps (needs texcoord1, texcoord2, and tangent)
+										normspec_faces.push_back(facep);
+									}
+									else
+									{ //has normal map (needs texcoord1 and tangent)
+										norm_faces.push_back(facep);
+									}
+								}
+								else if (mat->getSpecularID().notNull())
+								{ //has specular map but no normal map, needs texcoord2
+									spec_faces.push_back(facep);
+								}
+								else
+								{ //has neither specular map nor normal map, only needs texcoord0
+									simple_faces.push_back(facep);
+								}									
+							}
+							else if (te->getBumpmap())
+							{ //needs normal + tangent
 								bump_faces.push_back(facep);
 							}
 							else if (te->getShiny() || !te->getFullbright())
@@ -4575,7 +4809,7 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 						else
 						{
 							if (te->getBumpmap() && LLPipeline::sRenderBump)
-							{ //needs normal + binormal
+							{ //needs normal + tangent
 								bump_faces.push_back(facep);
 							}
 							else if ((te->getShiny() && LLPipeline::sRenderBump) ||
@@ -4616,32 +4850,38 @@ void LLVolumeGeometryManager::rebuildGeom(LLSpatialGroup* group)
 	U32 bump_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_NORMAL | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR;
 	U32 fullbright_mask = LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_COLOR;
 
+	U32 norm_mask = simple_mask | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TANGENT;
+	U32 normspec_mask = norm_mask | LLVertexBuffer::MAP_TEXCOORD2;
+	U32 spec_mask = simple_mask | LLVertexBuffer::MAP_TEXCOORD2;
+
 	if (emissive)
 	{ //emissive faces are present, include emissive byte to preserve batching
 		simple_mask = simple_mask | LLVertexBuffer::MAP_EMISSIVE;
 		alpha_mask = alpha_mask | LLVertexBuffer::MAP_EMISSIVE;
 		bump_mask = bump_mask | LLVertexBuffer::MAP_EMISSIVE;
 		fullbright_mask = fullbright_mask | LLVertexBuffer::MAP_EMISSIVE;
+		norm_mask = norm_mask | LLVertexBuffer::MAP_EMISSIVE;
+		normspec_mask = normspec_mask | LLVertexBuffer::MAP_EMISSIVE;
+		spec_mask = spec_mask | LLVertexBuffer::MAP_EMISSIVE;
 	}
 
-	bool batch_textures = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 1;
+	BOOL batch_textures = LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 1;
 
 	if (batch_textures)
 	{
-		bump_mask |= LLVertexBuffer::MAP_BINORMAL;
-		genDrawInfo(group, simple_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, simple_faces, FALSE, TRUE);
-		genDrawInfo(group, fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, fullbright_faces, FALSE, TRUE);
-		genDrawInfo(group, bump_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, bump_faces, FALSE, TRUE);
-		genDrawInfo(group, alpha_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, alpha_faces, TRUE, TRUE);
+		bump_mask = bump_mask | LLVertexBuffer::MAP_TANGENT;
+		simple_mask = simple_mask | LLVertexBuffer::MAP_TEXTURE_INDEX;
+		alpha_mask = alpha_mask | LLVertexBuffer::MAP_TEXTURE_INDEX | LLVertexBuffer::MAP_TANGENT | LLVertexBuffer::MAP_TEXCOORD1 | LLVertexBuffer::MAP_TEXCOORD2;
+		fullbright_mask = fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX;
 	}
-	else
-	{
-		genDrawInfo(group, simple_mask, simple_faces);
-		genDrawInfo(group, fullbright_mask, fullbright_faces);
-		genDrawInfo(group, bump_mask, bump_faces, FALSE, TRUE);
-		genDrawInfo(group, alpha_mask, alpha_faces, TRUE);
-	}
-	
+
+	genDrawInfo(group, simple_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, simple_faces, FALSE, batch_textures, FALSE);
+	genDrawInfo(group, fullbright_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, fullbright_faces, FALSE, batch_textures);
+	genDrawInfo(group, alpha_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, alpha_faces, TRUE, batch_textures);
+	genDrawInfo(group, bump_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, bump_faces, FALSE, FALSE);
+	genDrawInfo(group, norm_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, norm_faces, FALSE, FALSE);
+	genDrawInfo(group, spec_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, spec_faces, FALSE, FALSE);
+	genDrawInfo(group, normspec_mask | LLVertexBuffer::MAP_TEXTURE_INDEX, normspec_faces, FALSE, FALSE);
 
 	if (!LLPipeline::sDelayVBUpdate)
 	{
@@ -4793,11 +5033,18 @@ struct CompareBatchBreakerModified
 		{
 			return lte->getFullbright() < rte->getFullbright();
 		}
+		else if (LLPipeline::sRenderDeferred && lte->getMaterialParams() != rte->getMaterialParams())
+		{
+			return lte->getMaterialParams() < rte->getMaterialParams();
+		}
+		else if (LLPipeline::sRenderDeferred && (lte->getMaterialParams() == rte->getMaterialParams()) && (lte->getShiny() != rte->getShiny()))
+		{
+			return lte->getShiny() < rte->getShiny();
+		}
 		else
 		{
 			return lhs->getTexture() < rhs->getTexture();
 		}
-		
 	}
 };
 
@@ -4811,7 +5058,7 @@ static LLFastTimer::DeclareTimer FTM_GEN_DRAW_INFO_RESIZE_VB("Resize VB");
 
 
 
-void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort, BOOL batch_textures)
+void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::vector<LLFace*>& faces, BOOL distance_sort, BOOL batch_textures, BOOL no_materials)
 {
 	LLFastTimer t(FTM_REBUILD_VOLUME_GEN_DRAW_INFO);
 
@@ -4881,6 +5128,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 		//pull off next face
 		LLFace* facep = *face_iter;
 		LLViewerTexture* tex = facep->getTexture();
+		LLMaterialPtr mat = facep->getTextureEntry()->getMaterialParams();
 
 		if (distance_sort)
 		{
@@ -4926,6 +5174,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 						if (!can_batch_texture(facep))
 						{ //face is bump mapped or has an animated texture matrix -- can't 
 							//batch more than 1 texture at a time
+							facep->setTextureIndex(0);
 							break;
 						}
 
@@ -4976,13 +5225,20 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 						facep->setTextureIndex(cur_tex);
 					}
 				}
+				else
+				{
+					facep->setTextureIndex(0);
+				}
 
 				tex = texture_list[0];
 			}
 			else
 			{
 				while (i != faces.end() && 
-					(LLPipeline::sTextureBindTest || (distance_sort || (*i)->getTexture() == tex)))
+					(LLPipeline::sTextureBindTest || 
+						(distance_sort || 
+							((*i)->getTexture() == tex &&
+							((*i)->getTextureEntry()->getMaterialParams() == mat)))))
 				{
 					facep = *i;
 			
@@ -5068,8 +5324,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 
 			index_offset += facep->getGeomCount();
 			indices_index += facep->getIndicesCount();
-
-
+			
 			//append face to appropriate render batch
 
 			BOOL force_simple = facep->getPixelArea() < FORCE_SIMPLE_RENDER_AREA;
@@ -5089,7 +5344,130 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 
 			BOOL is_alpha = (facep->getPoolType() == LLDrawPool::POOL_ALPHA) ? TRUE : FALSE;
 		
-			if (is_alpha)
+			LLMaterial* mat = te->getMaterialParams().get();
+
+			bool can_be_shiny = true;
+			if (mat)
+			{
+				U8 mode = mat->getDiffuseAlphaMode();
+				can_be_shiny = mode == LLMaterial::DIFFUSE_ALPHA_MODE_NONE ||
+								mode == LLMaterial::DIFFUSE_ALPHA_MODE_EMISSIVE;
+			}
+
+			bool use_legacy_bump = te->getBumpmap() && (!mat || mat->getNormalID().isNull());
+
+			if (mat && LLPipeline::sRenderDeferred && !hud_group)
+			{
+				bool material_pass = false;
+
+				if (fullbright)
+				{
+					if (mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK)
+					{
+						if (te->getColor().mV[3] >= 0.999f)
+						{
+							material_pass = true;
+						}
+						else
+						{
+							registerFace(group, facep, LLRenderPass::PASS_ALPHA);
+						}
+					}
+					else if (is_alpha)
+					{
+						registerFace(group, facep, LLRenderPass::PASS_ALPHA);
+					}
+					else
+					{
+						if (mat->getEnvironmentIntensity() > 0 ||
+							te->getShiny() > 0)
+						{
+							material_pass = true;
+						}
+						else
+						{
+							registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT);
+						}
+					}
+				}
+				else if (no_materials)
+				{
+					registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
+				}
+				else if (te->getColor().mV[3] < 0.999f)
+				{
+					registerFace(group, facep, LLRenderPass::PASS_ALPHA);
+				}
+				else if (use_legacy_bump)
+				{
+					// we have a material AND legacy bump settings, but no normal map
+					registerFace(group, facep, LLRenderPass::PASS_BUMP);
+				}
+				else
+				{
+					material_pass = true;
+				}
+
+				if (material_pass)
+				{
+					U32 pass[] = 
+					{
+						LLRenderPass::PASS_MATERIAL,
+						LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_MATERIAL_ALPHA,
+						LLRenderPass::PASS_MATERIAL_ALPHA_MASK,
+						LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE,
+						LLRenderPass::PASS_SPECMAP,
+						LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_SPECMAP_BLEND,
+						LLRenderPass::PASS_SPECMAP_MASK,
+						LLRenderPass::PASS_SPECMAP_EMISSIVE,
+						LLRenderPass::PASS_NORMMAP,
+						LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_NORMMAP_BLEND,
+						LLRenderPass::PASS_NORMMAP_MASK,
+						LLRenderPass::PASS_NORMMAP_EMISSIVE,
+						LLRenderPass::PASS_NORMSPEC,
+						LLRenderPass::PASS_ALPHA, //LLRenderPass::PASS_NORMSPEC_BLEND,
+						LLRenderPass::PASS_NORMSPEC_MASK,
+						LLRenderPass::PASS_NORMSPEC_EMISSIVE,
+					};
+
+					U32 mask = mat->getShaderMask();
+
+					llassert(mask < sizeof(pass)/sizeof(U32));
+
+					mask = llmin(mask, (U32)(sizeof(pass)/sizeof(U32)-1));
+
+					registerFace(group, facep, pass[mask]);
+				}
+			}
+			else if (mat)
+			{
+				U8 mode = mat->getDiffuseAlphaMode();
+				if (te->getColor().mV[3] < 0.999f)
+				{
+					mode = LLMaterial::DIFFUSE_ALPHA_MODE_BLEND;
+				}
+
+				if (mode == LLMaterial::DIFFUSE_ALPHA_MODE_MASK)
+				{
+					registerFace(group, facep, fullbright ? LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK : LLRenderPass::PASS_ALPHA_MASK);
+				}
+				else if (is_alpha || (te->getColor().mV[3] < 0.999f))
+				{
+					registerFace(group, facep, LLRenderPass::PASS_ALPHA);
+				}
+				else if (gPipeline.canUseVertexShaders()
+					&& LLPipeline::sRenderBump 
+					&& te->getShiny() 
+					&& can_be_shiny)
+				{
+					registerFace(group, facep, fullbright ? LLRenderPass::PASS_FULLBRIGHT_SHINY : LLRenderPass::PASS_SHINY);
+				}
+				else
+				{
+					registerFace(group, facep, fullbright ? LLRenderPass::PASS_FULLBRIGHT : LLRenderPass::PASS_SIMPLE);
+				}
+			}
+			else if (is_alpha)
 			{
 				// can we safely treat this as an alpha mask?
 				if (facep->getFaceColor().mV[3] <= 0.f)
@@ -5114,7 +5492,8 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 			}
 			else if (gPipeline.canUseVertexShaders()
 				&& LLPipeline::sRenderBump 
-				&& te->getShiny())
+				&& te->getShiny() 
+				&& can_be_shiny)
 			{ //shiny
 				if (tex->getPrimaryFormat() == GL_ALPHA)
 				{ //invisiprim+shiny
@@ -5131,7 +5510,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 							registerFace(group, facep, LLRenderPass::PASS_POST_BUMP);
 						}
 					}
-					else if (te->getBumpmap())
+					else if (use_legacy_bump)
 					{ //register in deferred bump pass
 						registerFace(group, facep, LLRenderPass::PASS_BUMP);
 					}
@@ -5158,22 +5537,36 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 				}
 				else if (fullbright || bake_sunlight)
 				{ //fullbright
-					registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT);
-					if (LLPipeline::sRenderDeferred && !hud_group && LLPipeline::sRenderBump && te->getBumpmap())
+					if (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK)
+					{
+						registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK);
+					}
+					else
+					{
+						registerFace(group, facep, LLRenderPass::PASS_FULLBRIGHT);
+					}
+					if (LLPipeline::sRenderDeferred && !hud_group && LLPipeline::sRenderBump && use_legacy_bump)
 					{ //if this is the deferred render and a bump map is present, register in post deferred bump
 						registerFace(group, facep, LLRenderPass::PASS_POST_BUMP);
 					}
 				}
 				else
 				{
-					if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && te->getBumpmap())
+					if (LLPipeline::sRenderDeferred && LLPipeline::sRenderBump && use_legacy_bump)
 					{ //non-shiny or fullbright deferred bump
 						registerFace(group, facep, LLRenderPass::PASS_BUMP);
 					}
 					else
 					{ //all around simple
 						llassert(mask & LLVertexBuffer::MAP_NORMAL);
-						registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
+						if (mat && mat->getDiffuseAlphaMode() == LLMaterial::DIFFUSE_ALPHA_MODE_MASK)
+						{ //material alpha mask can be respected in non-deferred
+							registerFace(group, facep, LLRenderPass::PASS_ALPHA_MASK);
+						}
+						else
+						{
+							registerFace(group, facep, LLRenderPass::PASS_SIMPLE);
+						}
 					}
 				}
 				
@@ -5193,7 +5586,7 @@ void LLVolumeGeometryManager::genDrawInfo(LLSpatialGroup* group, U32 mask, std::
 				llassert((mask & LLVertexBuffer::MAP_NORMAL) || fullbright);
 				facep->setPoolType((fullbright) ? LLDrawPool::POOL_FULLBRIGHT : LLDrawPool::POOL_SIMPLE);
 				
-				if (!force_simple && te->getBumpmap() && LLPipeline::sRenderBump)
+				if (!force_simple && LLPipeline::sRenderBump && use_legacy_bump)
 				{
 					registerFace(group, facep, LLRenderPass::PASS_BUMP);
 				}
@@ -5282,4 +5675,3 @@ void LLHUDPartition::shift(const LLVector4a &offset)
 	//HUD objects don't shift with region crossing.  That would be silly.
 }
 
-
diff --git a/indra/newview/llvovolume.h b/indra/newview/llvovolume.h
index 5482c80f2b1ad146a72019f1e00ec64649330e52..7503f8c5aa8548a434c4ac32c25b1fa5c6fc90c6 100755
--- a/indra/newview/llvovolume.h
+++ b/indra/newview/llvovolume.h
@@ -31,12 +31,14 @@
 #include "llviewertexture.h"
 #include "llviewermedia.h"
 #include "llframetimer.h"
+#include "lllocalbitmaps.h"
 #include "m3math.h"		// LLMatrix3
 #include "m4math.h"		// LLMatrix4
 #include <map>
 
 class LLViewerTextureAnim;
 class LLDrawPool;
+class LLMaterialID;
 class LLSelectNode;
 class LLObjectMediaDataClient;
 class LLObjectMediaNavigateClient;
@@ -135,14 +137,14 @@ class LLVOVolume : public LLViewerObject
 
 	/*virtual*/ U32		getTriangleCount(S32* vcount = NULL) const;
 	/*virtual*/ U32		getHighLODTriangleCount();
-	/*virtual*/ BOOL lineSegmentIntersect(const LLVector3& start, const LLVector3& end, 
+	/*virtual*/ BOOL lineSegmentIntersect(const LLVector4a& start, const LLVector4a& end, 
 										  S32 face = -1,                        // which face to check, -1 = ALL_SIDES
 										  BOOL pick_transparent = FALSE,
 										  S32* face_hit = NULL,                 // which face was hit
-										  LLVector3* intersection = NULL,       // return the intersection point
+										  LLVector4a* intersection = NULL,       // return the intersection point
 										  LLVector2* tex_coord = NULL,          // return the texture coordinates of the intersection point
-										  LLVector3* normal = NULL,             // return the surface normal at the intersection point
-										  LLVector3* bi_normal = NULL           // return the surface bi-normal at the intersection point
+										  LLVector4a* normal = NULL,             // return the surface normal at the intersection point
+										  LLVector4a* tangent = NULL           // return the surface tangent at the intersection point
 		);
 	
 				LLVector3 agentPositionToVolume(const LLVector3& pos) const;
@@ -157,6 +159,7 @@ class LLVOVolume : public LLViewerObject
 				const LLMatrix4& getWorldMatrix(LLXformMatrix* xform) const;
 
 				void	markForUpdate(BOOL priority)			{ LLViewerObject::markForUpdate(priority); mVolumeChanged = TRUE; }
+				void    faceMappingChanged()                    { mFaceMappingChanged=TRUE; };
 
 	/*virtual*/ void	onShift(const LLVector4a &shift_vector); // Called when the drawable shifts
 
@@ -185,6 +188,11 @@ class LLVOVolume : public LLViewerObject
 	/*virtual*/ S32		setTEBumpShinyFullbright(const U8 te, const U8 bump);
 	/*virtual*/ S32		setTEMediaFlags(const U8 te, const U8 media_flags);
 	/*virtual*/ S32		setTEGlow(const U8 te, const F32 glow);
+	/*virtual*/ S32		setTEMaterialID(const U8 te, const LLMaterialID& pMaterialID);
+	
+	static void	setTEMaterialParamsCallbackTE(const LLUUID& objectID, const LLMaterialID& pMaterialID, const LLMaterialPtr pMaterialParams, U32 te);
+
+	/*virtual*/ S32		setTEMaterialParams(const U8 te, const LLMaterialPtr pMaterialParams);
 	/*virtual*/ S32		setTEScale(const U8 te, const F32 s, const F32 t);
 	/*virtual*/ S32		setTEScaleS(const U8 te, const F32 s);
 	/*virtual*/ S32		setTEScaleT(const U8 te, const F32 t);
@@ -378,3 +386,4 @@ class LLVOVolume : public LLViewerObject
 };
 
 #endif // LL_LLVOVOLUME_H
+
diff --git a/indra/newview/llwlparamset.cpp b/indra/newview/llwlparamset.cpp
index b04d30db5522a43071b84eafedc35c94fb2a8165..dba397063572aba709f25901fef95951e9ffe4a1 100755
--- a/indra/newview/llwlparamset.cpp
+++ b/indra/newview/llwlparamset.cpp
@@ -33,6 +33,7 @@
 #include "llglslshader.h"
 #include "lluictrlfactory.h"
 #include "llsliderctrl.h"
+#include "pipeline.h"
 
 #include <llgl.h>
 
@@ -127,6 +128,13 @@ void LLWLParamSet::update(LLGLSLShader * shader) const
 			}
 		}
 	}
+	
+	if (LLPipeline::sRenderDeferred && !LLPipeline::sReflectionRender && !LLPipeline::sUnderWaterRender)
+	{
+		shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 2.2);
+	} else {
+		shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 1.0);
+	}
 }
 
 void LLWLParamSet::set(const std::string& paramName, float x) 
diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp
index 793becf0c82e14397692d9838e7d0ccb4926129b..7996f8a64005b31f6e1b3f58f93877639b46c7c5 100755
--- a/indra/newview/llworld.cpp
+++ b/indra/newview/llworld.cpp
@@ -274,7 +274,9 @@ void LLWorld::removeRegion(const LLHost &host)
 	mActiveRegionList.remove(regionp);
 	mCulledRegionList.remove(regionp);
 	mVisibleRegionList.remove(regionp);
-	
+
+	mRegionRemovedSignal(regionp);
+
 	delete regionp;
 
 	updateWaterObjects();
@@ -402,6 +404,19 @@ LLViewerRegion* LLWorld::getRegionFromHandle(const U64 &handle)
 	return NULL;
 }
 
+LLViewerRegion* LLWorld::getRegionFromID(const LLUUID& region_id)
+{
+	for (region_list_t::iterator iter = mRegionList.begin();
+		 iter != mRegionList.end(); ++iter)
+	{
+		LLViewerRegion* regionp = *iter;
+		if (regionp->getRegionID() == region_id)
+		{
+			return regionp;
+		}
+	}
+	return NULL;
+}
 
 void LLWorld::updateAgentOffset(const LLVector3d &offset_global)
 {
@@ -1244,6 +1259,11 @@ bool LLWorld::isRegionListed(const LLViewerRegion* region) const
 	return it != mRegionList.end();
 }
 
+boost::signals2::connection LLWorld::setRegionRemovedCallback(const region_remove_signal_t::slot_type& cb)
+{
+	return mRegionRemovedSignal.connect(cb);
+}
+
 LLHTTPRegistration<LLEstablishAgentCommunication>
 	gHTTPRegistrationEstablishAgentCommunication(
 							"/message/EstablishAgentCommunication");
diff --git a/indra/newview/llworld.h b/indra/newview/llworld.h
index f350009d100c09f6d10f4b0cc4f1014716f88995..d0b001ba443fef1022ae957ace3144d2923e7c5e 100755
--- a/indra/newview/llworld.h
+++ b/indra/newview/llworld.h
@@ -76,6 +76,7 @@ class LLWorld : public LLSingleton<LLWorld>
 	LLViewerRegion*			getRegionFromPosGlobal(const LLVector3d &pos);
 	LLViewerRegion*			getRegionFromPosAgent(const LLVector3 &pos);
 	LLViewerRegion*			getRegionFromHandle(const U64 &handle);
+	LLViewerRegion*			getRegionFromID(const LLUUID& region_id);
 	BOOL					positionRegionValidGlobal(const LLVector3d& pos);			// true if position is in valid region
 	LLVector3d				clipToVisibleRegions(const LLVector3d &start_pos, const LLVector3d &end_pos);
 
@@ -149,6 +150,9 @@ class LLWorld : public LLSingleton<LLWorld>
 	typedef std::list<LLViewerRegion*> region_list_t;
 	const region_list_t& getRegionList() const { return mActiveRegionList; }
 
+	typedef boost::signals2::signal<void(LLViewerRegion*)> region_remove_signal_t;
+	boost::signals2::connection setRegionRemovedCallback(const region_remove_signal_t::slot_type& cb);
+
 	// Returns lists of avatar IDs and their world-space positions within a given distance of a point.
 	// All arguments are optional. Given containers will be emptied and then filled.
 	// Not supplying origin or radius input returns data on all avatars in the known regions.
@@ -168,6 +172,8 @@ class LLWorld : public LLSingleton<LLWorld>
 	region_list_t	mVisibleRegionList;
 	region_list_t	mCulledRegionList;
 
+	region_remove_signal_t mRegionRemovedSignal;
+
 	// Number of points on edge
 	static const U32 mWidth;
 
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 7eed9acb4bf20adbbebf3593b66efe752522fba6..c25d22bbdf77f0b77072eecd5c88df9de6bb2981 100755
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -233,6 +233,7 @@ LLFastTimer::DeclareTimer FTM_RENDER_WL_SKY("Windlight Sky");
 LLFastTimer::DeclareTimer FTM_RENDER_ALPHA("Alpha Objects");
 LLFastTimer::DeclareTimer FTM_RENDER_CHARACTERS("Avatars");
 LLFastTimer::DeclareTimer FTM_RENDER_BUMP("Bump");
+LLFastTimer::DeclareTimer FTM_RENDER_MATERIALS("Materials");
 LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT("Fullbright");
 LLFastTimer::DeclareTimer FTM_RENDER_GLOW("Glow");
 LLFastTimer::DeclareTimer FTM_GEO_UPDATE("Geo Update");
@@ -262,10 +263,13 @@ std::string gPoolNames[] =
 	"POOL_GROUND",
 	"POOL_FULLBRIGHT",
 	"POOL_BUMP",
+	"POOL_MATERIALS",
 	"POOL_TERRAIN,"	
 	"POOL_SKY",
 	"POOL_WL_SKY",
 	"POOL_TREE",
+	"POOL_ALPHA_MASK",
+	"POOL_FULLBRIGHT_ALPHA_MASK",
 	"POOL_GRASS",
 	"POOL_INVISIBLE",
 	"POOL_AVATAR",
@@ -275,7 +279,7 @@ std::string gPoolNames[] =
 	"POOL_ALPHA"
 };
 
-void drawBox(const LLVector3& c, const LLVector3& r);
+void drawBox(const LLVector4a& c, const LLVector4a& r);
 void drawBoxOutline(const LLVector3& pos, const LLVector3& size);
 U32 nhpo2(U32 v);
 LLVertexBuffer* ll_create_cube_vb(U32 type_mask, U32 usage);
@@ -352,6 +356,7 @@ BOOL	LLPipeline::sRenderParticleBeacons = FALSE;
 BOOL	LLPipeline::sRenderSoundBeacons = FALSE;
 BOOL	LLPipeline::sRenderBeacons = FALSE;
 BOOL	LLPipeline::sRenderHighlight = TRUE;
+LLRender::eTexIndex LLPipeline::sRenderHighlightTextureChannel = LLRender::DIFFUSE_MAP;
 BOOL	LLPipeline::sForceOldBakedUpload = FALSE;
 S32		LLPipeline::sUseOcclusion = 0;
 BOOL	LLPipeline::sDelayVBUpdate = TRUE;
@@ -377,6 +382,7 @@ BOOL	LLPipeline::sRenderDeferred = FALSE;
 BOOL    LLPipeline::sMemAllocationThrottled = FALSE;
 S32		LLPipeline::sVisibleLightCount = 0;
 F32		LLPipeline::sMinRenderSize = 0.f;
+BOOL	LLPipeline::sRenderingHUDs;
 
 // EventHost API LLPipeline listener.
 static LLPipelineListener sPipelineListener;
@@ -398,8 +404,8 @@ void validate_framebuffer_object();
 
 bool addDeferredAttachments(LLRenderTarget& target)
 {
-	return target.addColorAttachment(GL_RGBA) && //specular
-			target.addColorAttachment(GL_RGBA); //normal+z	
+	return target.addColorAttachment(GL_SRGB8_ALPHA8) && //specular
+			target.addColorAttachment(GL_RGB10_A2); //normal+z
 }
 
 LLPipeline::LLPipeline() :
@@ -435,10 +441,14 @@ LLPipeline::LLPipeline() :
 	mWaterPool(NULL),
 	mGroundPool(NULL),
 	mSimplePool(NULL),
+	mGrassPool(NULL),
+	mAlphaMaskPool(NULL),
+	mFullbrightAlphaMaskPool(NULL),
 	mFullbrightPool(NULL),
 	mInvisiblePool(NULL),
 	mGlowPool(NULL),
 	mBumpPool(NULL),
+	mMaterialsPool(NULL),
 	mWLSkyPool(NULL),
 	mLightMask(0),
 	mLightMovingMask(0),
@@ -485,10 +495,13 @@ void LLPipeline::init()
 	//create render pass pools
 	getPool(LLDrawPool::POOL_ALPHA);
 	getPool(LLDrawPool::POOL_SIMPLE);
+	getPool(LLDrawPool::POOL_ALPHA_MASK);
+	getPool(LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK);
 	getPool(LLDrawPool::POOL_GRASS);
 	getPool(LLDrawPool::POOL_FULLBRIGHT);
 	getPool(LLDrawPool::POOL_INVISIBLE);
 	getPool(LLDrawPool::POOL_BUMP);
+	getPool(LLDrawPool::POOL_MATERIALS);
 	getPool(LLDrawPool::POOL_GLOW);
 
 	LLViewerStats::getInstance()->mTrianglesDrawnStat.reset();
@@ -916,12 +929,26 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 		S32 shadow_detail = RenderShadowDetail;
 		BOOL ssao = RenderDeferredSSAO;
 		
+		const U32 occlusion_divisor = 3;
+
 		//allocate deferred rendering color buffers
-		if (!mDeferredScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
+		if (!mDeferredScreen.allocate(resX, resY, GL_SRGB8_ALPHA8, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
 		if (!mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
+		if (!mOcclusionDepth.allocate(resX/occlusion_divisor, resY/occlusion_divisor, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
 		if (!addDeferredAttachments(mDeferredScreen)) return false;
-	
-		if (!mScreen.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
+		
+		GLuint screenFormat = GL_RGBA16;
+		if (gGLManager.mIsATI)
+		{
+			screenFormat = GL_RGBA12;
+		}
+
+		if (gGLManager.mGLVersion < 4.f && gGLManager.mIsNVIDIA)
+		{
+			screenFormat = GL_RGBA16F_ARB;
+		}
+		
+		if (!mScreen.allocate(resX, resY, screenFormat, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE, samples)) return false;
 		if (samples > 0)
 		{
 			if (!mFXAABuffer.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_TEXTURE, FALSE, samples)) return false;
@@ -948,6 +975,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 			for (U32 i = 0; i < 4; i++)
 			{
 				if (!mShadow[i].allocate(sun_shadow_map_width,U32(resY*scale), 0, TRUE, FALSE, LLTexUnit::TT_TEXTURE)) return false;
+				if (!mShadowOcclusion[i].allocate(mShadow[i].getWidth()/occlusion_divisor, mShadow[i].getHeight()/occlusion_divisor, 0, TRUE, FALSE, LLTexUnit::TT_TEXTURE)) return false;
 			}
 		}
 		else
@@ -955,6 +983,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 			for (U32 i = 0; i < 4; i++)
 			{
 				mShadow[i].release();
+				mShadowOcclusion[i].release();
 			}
 		}
 
@@ -967,6 +996,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 			for (U32 i = 4; i < 6; i++)
 			{
 				if (!mShadow[i].allocate(spot_shadow_map_width, height, 0, TRUE, FALSE)) return false;
+				if (!mShadowOcclusion[i].allocate(mShadow[i].getWidth()/occlusion_divisor, mShadow[i].getHeight()/occlusion_divisor, 0, TRUE, FALSE)) return false;
 			}
 		}
 		else
@@ -974,6 +1004,7 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 			for (U32 i = 4; i < 6; i++)
 			{
 				mShadow[i].release();
+				mShadowOcclusion[i].release();
 			}
 		}
 
@@ -990,11 +1021,13 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 		for (U32 i = 0; i < 6; i++)
 		{
 			mShadow[i].release();
+			mShadowOcclusion[i].release();
 		}
 		mFXAABuffer.release();
 		mScreen.release();
 		mDeferredScreen.release(); //make sure to release any render targets that share a depth buffer with mDeferredScreen first
 		mDeferredDepth.release();
+		mOcclusionDepth.release();
 						
 		if (!mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE)) return false;		
 	}
@@ -1011,12 +1044,19 @@ bool LLPipeline::allocateScreenBuffer(U32 resX, U32 resY, U32 samples)
 	return true;
 }
 
+//static
+void LLPipeline::updateRenderBump()
+{
+	sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
+}
+
 //static
 void LLPipeline::updateRenderDeferred()
 {
 	BOOL deferred = ((RenderDeferred && 
 					 LLRenderTarget::sUseFBO &&
-					 LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&	 
+					 LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
+					 LLPipeline::sRenderBump &&
 					 VertexShaderEnable && 
 					 RenderAvatarVP &&
 					 WindLightUseAtmosShaders) ? TRUE : FALSE) &&
@@ -1159,7 +1199,7 @@ void LLPipeline::releaseLUTBuffers()
 {
 	if (mLightFunc)
 	{
-		LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, GL_R8, 0, 1, &mLightFunc);
+		LLImageGL::deleteTextures(LLTexUnit::TT_TEXTURE, GL_R16F, 0, 1, &mLightFunc);
 		mLightFunc = 0;
 	}
 }
@@ -1213,7 +1253,7 @@ void LLPipeline::createGLBuffers()
 
 		for (U32 i = 0; i < 3; i++)
 		{
-			mGlow[i].allocate(512,glow_res,GL_RGBA,FALSE,FALSE);
+			mGlow[i].allocate(512,glow_res, GL_RGBA,FALSE,FALSE);
 		}
 
 		allocateScreenBuffer(resX,resY);
@@ -1264,13 +1304,18 @@ void LLPipeline::createGLBuffers()
 	gBumpImageList.restoreGL();
 }
 
+F32 lerpf(F32 a, F32 b, F32 w)
+{
+	return a + w * (b - a);
+}
+
 void LLPipeline::createLUTBuffers()
 {
 	if (sRenderDeferred)
 	{
 		if (!mLightFunc)
 		{
-			U32 lightResX = gSavedSettings.getU32("RenderSpecularResX");
+			/*U32 lightResX = gSavedSettings.getU32("RenderSpecularResX");
 			U32 lightResY = gSavedSettings.getU32("RenderSpecularResY");
 			U8* ls = new U8[lightResX*lightResY];
 			F32 specExp = gSavedSettings.getF32("RenderSpecularExponent");
@@ -1306,13 +1351,62 @@ void LLPipeline::createLUTBuffers()
 					// Combined with a bit of noise and trilinear filtering, the banding is hardly noticable.
 					ls[y*lightResX+x] = (U8)(llclamp(spec * (1.f / 6), 0.f, 1.f) * 255);
 				}
+			}*/
+		
+
+			U32 lightResX = gSavedSettings.getU32("RenderSpecularResX");
+			U32 lightResY = gSavedSettings.getU32("RenderSpecularResY");
+			F32* ls = new F32[lightResX*lightResY];
+			//F32 specExp = gSavedSettings.getF32("RenderSpecularExponent"); // Note: only use this when creating new specular lighting functions.
+            // Calculate the (normalized) blinn-phong specular lookup texture. (with a few tweaks)
+			for (U32 y = 0; y < lightResY; ++y)
+			{
+				for (U32 x = 0; x < lightResX; ++x)
+				{
+					ls[y*lightResX+x] = 0;
+					F32 sa = (F32) x/(lightResX-1);
+					F32 spec = (F32) y/(lightResY-1);
+					F32 n = spec * spec * 368;
+					
+					// Nothing special here.  Just your typical blinn-phong term.
+					spec = powf(sa, n);
+					
+					// Apply our normalization function.
+					// Note: This is the full equation that applies the full normalization curve, not an approximation.
+					// This is fine, given we only need to create our LUT once per buffer initialization.
+					spec *= (((n + 2) * (n + 4)) / (8 * F_PI * (powf(2, -n/2) + n)));
+
+					// Since we use R16F, we no longer have a dynamic range issue we need to work around here.
+					// Though some older drivers may not like this, newer drivers shouldn't have this problem.
+					ls[y*lightResX+x] = spec;
+
+					
+					//beckmann distribution
+					/*F32 alpha = acosf((F32) x/(lightResX-1));
+					F32 m = 1.f - (F32) y/(lightResY-1);
+
+					F32 cos4_alpha = cosf(alpha);
+					cos4_alpha *= cos4_alpha;
+					cos4_alpha *= cos4_alpha;
+
+					F32 tan_alpha = tanf(alpha);
+					F32 tan2_alpha = tan_alpha*tan_alpha;
+
+					F32 k = expf(-(tan2_alpha)/(m*m)) /
+						(3.14159f*m*m*cos4_alpha);
+
+					ls[y*lightResX+x] = k;*/
+				}
 			}
 			
-			LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, GL_R8, 1, &mLightFunc);
+			LLImageGL::generateTextures(LLTexUnit::TT_TEXTURE, GL_R16F, 1, &mLightFunc);
 			gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc);
-			LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_R8, lightResX, lightResY, GL_RED, GL_UNSIGNED_BYTE, ls, false);
+			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, 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);
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
 			
 			delete [] ls;
 		}
@@ -1516,6 +1610,14 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0)
 		poolp = mGrassPool;
 		break;
 
+	case LLDrawPool::POOL_ALPHA_MASK:
+		poolp = mAlphaMaskPool;
+		break;
+
+	case LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK:
+		poolp = mFullbrightAlphaMaskPool;
+		break;
+
 	case LLDrawPool::POOL_FULLBRIGHT:
 		poolp = mFullbrightPool;
 		break;
@@ -1539,7 +1641,9 @@ LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0)
 	case LLDrawPool::POOL_BUMP:
 		poolp = mBumpPool;
 		break;
-
+	case LLDrawPool::POOL_MATERIALS:
+		poolp = mMaterialsPool;
+		break;
 	case LLDrawPool::POOL_ALPHA:
 		poolp = mAlphaPool;
 		break;
@@ -1603,20 +1707,44 @@ U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerTexture* ima
 		return 0;
 	}
 		
-	bool alpha = te->getColor().mV[3] < 0.999f;
+	LLMaterial* mat = te->getMaterialParams().get();
+
+	bool color_alpha = te->getColor().mV[3] < 0.999f;
+	bool alpha = color_alpha;
 	if (imagep)
 	{
 		alpha = alpha || (imagep->getComponents() == 4 && imagep->getType() != LLViewerTexture::MEDIA_TEXTURE) || (imagep->getComponents() == 2);
 	}
-
+	
+	if (alpha && mat)
+	{
+		switch (mat->getDiffuseAlphaMode())
+		{
+			case 1:
+				alpha = true; // Material's alpha mode is set to blend.  Toss it into the alpha draw pool.
+				break;
+			case 0: //alpha mode set to none, never go to alpha pool
+			case 3: //alpha mode set to emissive, never go to alpha pool
+				alpha = color_alpha;
+				break;
+			default: //alpha mode set to "mask", go to alpha pool if fullbright
+				alpha = color_alpha; // Material's alpha mode is set to none, mask, or emissive.  Toss it into the opaque material draw pool.
+				break;
+		}
+	}
+	
 	if (alpha)
 	{
 		return LLDrawPool::POOL_ALPHA;
 	}
-	else if ((te->getBumpmap() || te->getShiny()))
+	else if ((te->getBumpmap() || te->getShiny()) && (!mat || mat->getNormalID().isNull()))
 	{
 		return LLDrawPool::POOL_BUMP;
 	}
+	else if (mat && !alpha)
+	{
+		return LLDrawPool::POOL_MATERIALS;
+	}
 	else
 	{
 		return LLDrawPool::POOL_SIMPLE;
@@ -2312,7 +2440,14 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 
 	if (to_texture)
 	{
-		mScreen.bindTarget();
+		if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+		{
+			mOcclusionDepth.bindTarget();
+		}
+		else
+		{
+			mScreen.bindTarget();
+		}
 	}
 
 	if (sUseOcclusion > 1)
@@ -2450,7 +2585,14 @@ void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_cl
 
 	if (to_texture)
 	{
-		mScreen.flush();
+		if (LLPipeline::sRenderDeferred && !LLPipeline::sUnderWaterRender)
+		{
+			mOcclusionDepth.flush();
+		}
+		else
+		{
+			mScreen.flush();
+		}
 	}
 }
 
@@ -2518,6 +2660,73 @@ void LLPipeline::markOccluder(LLSpatialGroup* group)
 	}
 }
 
+void LLPipeline::downsampleDepthBuffer(LLRenderTarget& source, LLRenderTarget& dest, LLRenderTarget* scratch_space)
+{
+	LLGLSLShader* last_shader = LLGLSLShader::sCurBoundShaderPtr;
+
+	LLGLSLShader* shader = NULL;
+
+	if (scratch_space)
+	{
+		scratch_space->copyContents(source, 
+									0, 0, source.getWidth(), source.getHeight(), 
+									0, 0, scratch_space->getWidth(), scratch_space->getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+	}
+
+	dest.bindTarget();
+	dest.clear(GL_DEPTH_BUFFER_BIT);
+
+	LLStrider<LLVector3> vert; 
+	mDeferredVB->getVertexStrider(vert);
+	LLStrider<LLVector2> tc0;
+		
+	vert[0].set(-1,1,0);
+	vert[1].set(-1,-3,0);
+	vert[2].set(3,1,0);
+	
+	if (source.getUsage() == LLTexUnit::TT_RECT_TEXTURE)
+	{
+		shader = &gDownsampleDepthRectProgram;
+		shader->bind();
+		shader->uniform2f("delta", 1.f, 1.f);
+		shader->uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, source.getWidth(), source.getHeight());
+	}
+	else
+	{
+		shader = &gDownsampleDepthProgram;
+		shader->bind();
+		shader->uniform2f("delta", 1.f/source.getWidth(), 1.f/source.getHeight());
+		shader->uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, 1.f, 1.f);
+	}
+
+	gGL.getTexUnit(0)->bind(scratch_space ? scratch_space : &source, TRUE);
+
+	{
+		LLGLDepthTest depth(GL_TRUE, GL_TRUE, GL_ALWAYS);
+		mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+		mDeferredVB->drawArrays(LLRender::TRIANGLES, 0, 3);
+	}
+	
+	dest.flush();
+	
+	if (last_shader)
+	{
+		last_shader->bind();
+	}
+	else
+	{
+		shader->unbind();
+	}
+}
+
+void LLPipeline::doOcclusion(LLCamera& camera, LLRenderTarget& source, LLRenderTarget& dest, LLRenderTarget* scratch_space)
+{
+	downsampleDepthBuffer(source, dest, scratch_space);
+	dest.bindTarget();
+	doOcclusion(camera);
+	dest.flush();
+}
+
 void LLPipeline::doOcclusion(LLCamera& camera)
 {
 	if (LLPipeline::sUseOcclusion > 1 && sCull->hasOcclusionGroups())
@@ -3579,8 +3788,8 @@ void LLPipeline::postSort(LLCamera& camera)
 	for (LLCullResult::sg_iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
 	{
 		LLSpatialGroup* group = *i;
-		if (sUseOcclusion && 
-			group->isOcclusionState(LLSpatialGroup::OCCLUDED) ||
+		if ((sUseOcclusion && 
+			group->isOcclusionState(LLSpatialGroup::OCCLUDED)) ||
 			(RenderAutoHideSurfaceAreaLimit > 0.f && 
 			group->mSurfaceArea > RenderAutoHideSurfaceAreaLimit*llmax(group->mObjectBoxSize, 10.f)))
 		{
@@ -3746,7 +3955,9 @@ void LLPipeline::postSort(LLCamera& camera)
 	if (!sShadowRender)
 	{
 		mSelectedFaces.clear();
-		
+
+		LLPipeline::setRenderHighlightTextureChannel(LLSelectMgr::getInstance()->getTextureChannel());
+
 		// Draw face highlights for selected faces.
 		if (LLSelectMgr::getInstance()->getTEMode())
 		{
@@ -3969,13 +4180,14 @@ void LLPipeline::renderHighlights()
 		gGL.diffuseColor4f(1,1,1,0.5f);
 	}
 	
-	if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED))
+	if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED) && !mFaceSelectImagep)
+	{
+		mFaceSelectImagep = LLViewerTextureManager::getFetchedTexture(IMG_FACE_SELECT);
+	}
+
+	if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED) && (sRenderHighlightTextureChannel == LLRender::DIFFUSE_MAP))
 	{
 		// Make sure the selection image gets downloaded and decoded
-		if (!mFaceSelectImagep)
-		{
-			mFaceSelectImagep = LLViewerTextureManager::getFetchedTexture(IMG_FACE_SELECT);
-		}
 		mFaceSelectImagep->addTextureStats((F32)MAX_IMAGE_AREA);
 
 		U32 count = mSelectedFaces.size();
@@ -3991,7 +4203,7 @@ void LLPipeline::renderHighlights()
 			facep->renderSelected(mFaceSelectImagep, color);
 		}
 	}
-
+	
 	if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED))
 	{
 		// Paint 'em red!
@@ -4013,6 +4225,67 @@ void LLPipeline::renderHighlights()
 	{
 		gHighlightProgram.unbind();
 	}
+
+
+	if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED) && (sRenderHighlightTextureChannel == LLRender::NORMAL_MAP))
+	{
+		color.setVec(1.0f, 0.5f, 0.5f, 0.5f);
+		if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0))
+		{
+			gHighlightNormalProgram.bind();
+			gGL.diffuseColor4f(1,1,1,0.5f);
+		}
+
+		mFaceSelectImagep->addTextureStats((F32)MAX_IMAGE_AREA);
+
+		U32 count = mSelectedFaces.size();
+		for (U32 i = 0; i < count; i++)
+		{
+			LLFace *facep = mSelectedFaces[i];
+			if (!facep || facep->getDrawable()->isDead())
+			{
+				llerrs << "Bad face on selection" << llendl;
+				return;
+			}
+
+			facep->renderSelected(mFaceSelectImagep, color);
+		}
+
+		if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0))
+		{
+			gHighlightNormalProgram.unbind();
+		}
+	}
+
+	if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED) && (sRenderHighlightTextureChannel == LLRender::SPECULAR_MAP))
+	{
+		color.setVec(0.0f, 0.3f, 1.0f, 0.8f);
+		if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0))
+		{
+			gHighlightSpecularProgram.bind();
+			gGL.diffuseColor4f(1,1,1,0.5f);
+		}
+
+		mFaceSelectImagep->addTextureStats((F32)MAX_IMAGE_AREA);
+
+		U32 count = mSelectedFaces.size();
+		for (U32 i = 0; i < count; i++)
+		{
+			LLFace *facep = mSelectedFaces[i];
+			if (!facep || facep->getDrawable()->isDead())
+			{
+				llerrs << "Bad face on selection" << llendl;
+				return;
+			}
+
+			facep->renderSelected(mFaceSelectImagep, color);
+		}
+
+		if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0))
+		{
+			gHighlightSpecularProgram.unbind();
+		}
+	}
 }
 
 //debug use
@@ -4366,7 +4639,7 @@ void LLPipeline::renderGeomDeferred(LLCamera& camera)
 	gGL.setColorMask(true, false);
 }
 
-void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
+void LLPipeline::renderGeomPostDeferred(LLCamera& camera, bool do_occlusion)
 {
 	LLFastTimer t(FTM_POST_DEFERRED_POOLS);
 	U32 cur_type = 0;
@@ -4381,7 +4654,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
 	gGL.setColorMask(true, false);
 
 	pool_set_t::iterator iter1 = mPools.begin();
-	BOOL occlude = LLPipeline::sUseOcclusion > 1;
+	BOOL occlude = LLPipeline::sUseOcclusion > 1 && do_occlusion;
 
 	while ( iter1 != mPools.end() )
 	{
@@ -4395,7 +4668,7 @@ void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
 			gGLLastMatrix = NULL;
 			gGL.loadMatrix(gGLModelView);
 			LLGLSLShader::bindNoShader();
-			doOcclusion(camera);
+			doOcclusion(camera, mScreen, mOcclusionDepth, &mDeferredDepth);
 			gGL.setColorMask(true, false);
 		}
 
@@ -4613,6 +4886,7 @@ void LLPipeline::renderPhysicsDisplay()
 	mPhysicsDisplay.flush();
 }
 
+extern std::set<LLSpatialGroup*> visible_selected_groups;
 
 void LLPipeline::renderDebug()
 {
@@ -5002,8 +5276,8 @@ void LLPipeline::renderDebug()
 			LLSpatialPartition* part = region->getSpatialPartition(i);
 			if (part)
 			{
-				if ( hud_only && (part->mDrawableType == RENDER_TYPE_HUD || part->mDrawableType == RENDER_TYPE_HUD_PARTICLES) ||
-					 !hud_only && hasRenderType(part->mDrawableType) )
+				if ( (hud_only && (part->mDrawableType == RENDER_TYPE_HUD || part->mDrawableType == RENDER_TYPE_HUD_PARTICLES)) ||
+					 (!hud_only && hasRenderType(part->mDrawableType)) )
 				{
 					part->renderDebug();
 				}
@@ -5023,6 +5297,27 @@ void LLPipeline::renderDebug()
 		}
 	}
 
+	if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION) && LLGLSLShader::sNoFixedFunction)
+	{ //render visible selected group occlusion geometry
+		gDebugProgram.bind();
+		LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+		gGL.diffuseColor3f(1,0,1);
+		for (std::set<LLSpatialGroup*>::iterator iter = visible_selected_groups.begin(); iter != visible_selected_groups.end(); ++iter)
+		{
+			LLSpatialGroup* group = *iter;
+
+			LLVector4a fudge;
+			fudge.splat(0.25f); //SG_OCCLUSION_FUDGE
+
+			LLVector4a size;
+			size.setAdd(fudge, group->mBounds[1]);
+
+			drawBox(group->mBounds[0], size);
+		}
+	}
+
+	visible_selected_groups.clear();
+
 	if (LLGLSLShader::sNoFixedFunction)
 	{
 		gUIProgram.bind();
@@ -5318,6 +5613,32 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp )
 		}
 		break;
 
+	case LLDrawPool::POOL_ALPHA_MASK:
+		if (mAlphaMaskPool)
+		{
+			llassert(0);
+			llwarns << "Ignoring duplicate alpha mask pool." << llendl;
+			break;
+		}
+		else
+		{
+			mAlphaMaskPool = (LLRenderPass*) new_poolp;
+		}
+		break;
+
+	case LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK:
+		if (mFullbrightAlphaMaskPool)
+		{
+			llassert(0);
+			llwarns << "Ignoring duplicate alpha mask pool." << llendl;
+			break;
+		}
+		else
+		{
+			mFullbrightAlphaMaskPool = (LLRenderPass*) new_poolp;
+		}
+		break;
+		
 	case LLDrawPool::POOL_GRASS:
 		if (mGrassPool)
 		{
@@ -5385,7 +5706,17 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp )
 			mBumpPool = new_poolp;
 		}
 		break;
-
+	case LLDrawPool::POOL_MATERIALS:
+		if (mMaterialsPool)
+		{
+			llassert(0);
+			llwarns << "Ignorning duplicate materials pool." << llendl;
+		}
+		else
+		{
+			mMaterialsPool = new_poolp;
+		}
+		break;
 	case LLDrawPool::POOL_ALPHA:
 		if( mAlphaPool )
 		{
@@ -5394,7 +5725,7 @@ void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp )
 		}
 		else
 		{
-			mAlphaPool = new_poolp;
+			mAlphaPool = (LLDrawPoolAlpha*) new_poolp;
 		}
 		break;
 
@@ -5474,6 +5805,16 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
 		mSimplePool = NULL;
 		break;
 
+	case LLDrawPool::POOL_ALPHA_MASK:
+		llassert(mAlphaMaskPool == poolp);
+		mAlphaMaskPool = NULL;
+		break;
+
+	case LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK:
+		llassert(mFullbrightAlphaMaskPool == poolp);
+		mFullbrightAlphaMaskPool = NULL;
+		break;
+
 	case LLDrawPool::POOL_GRASS:
 		llassert(mGrassPool == poolp);
 		mGrassPool = NULL;
@@ -5525,7 +5866,12 @@ void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
 		llassert( poolp == mBumpPool );
 		mBumpPool = NULL;
 		break;
-	
+			
+	case LLDrawPool::POOL_MATERIALS:
+		llassert(poolp == mMaterialsPool);
+		mMaterialsPool = NULL;
+		break;
+			
 	case LLDrawPool::POOL_ALPHA:
 		llassert( poolp == mAlphaPool );
 		mAlphaPool = NULL;
@@ -5588,8 +5934,15 @@ void LLPipeline::setupAvatarLights(BOOL for_edit)
 
 		LLLightState* light = gGL.getLight(1);
 
-		mHWLightColors[1] = diffuse;
+		if (LLPipeline::sRenderDeferred)
+		{
+			/*diffuse.mV[0] = powf(diffuse.mV[0], 2.2f);
+			diffuse.mV[1] = powf(diffuse.mV[1], 2.2f);
+			diffuse.mV[2] = powf(diffuse.mV[2], 2.2f);*/
+		}
 
+		mHWLightColors[1] = diffuse;
+				
 		light->setDiffuse(diffuse);
 		light->setAmbient(LLColor4::black);
 		light->setSpecular(LLColor4::black);
@@ -5628,6 +5981,13 @@ void LLPipeline::setupAvatarLights(BOOL for_edit)
 		}
 		backlight_diffuse *= backlight_mag / max_component;
 
+		if (LLPipeline::sRenderDeferred)
+		{
+			/*backlight_diffuse.mV[0] = powf(backlight_diffuse.mV[0], 2.2f);
+			backlight_diffuse.mV[1] = powf(backlight_diffuse.mV[1], 2.2f);
+			backlight_diffuse.mV[2] = powf(backlight_diffuse.mV[2], 2.2f);*/
+		}
+
 		mHWLightColors[1] = backlight_diffuse;
 
 		LLLightState* light = gGL.getLight(1);
@@ -5834,6 +6194,14 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
 
 		LLVector4 light_pos(mSunDir, 0.0f);
 		LLColor4 light_diffuse = mSunDiffuse;
+
+		if (LLPipeline::sRenderDeferred)
+		{
+			/*light_diffuse.mV[0] = powf(light_diffuse.mV[0], 2.2f);
+			light_diffuse.mV[1] = powf(light_diffuse.mV[1], 2.2f);
+			light_diffuse.mV[2] = powf(light_diffuse.mV[2], 2.2f);*/
+		}
+
 		mHWLightColors[0] = light_diffuse;
 
 		LLLightState* light = gGL.getLight(0);
@@ -5902,6 +6270,13 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
 			F32 x = (3.f * (1.f + light->getLightFalloff())); // why this magic?  probably trying to match a historic behavior.
 			float linatten = x / (light_radius); // % of brightness at radius
 
+			if (LLPipeline::sRenderDeferred)
+			{
+				/*light_color.mV[0] = powf(light_color.mV[0], 2.2f);
+				light_color.mV[1] = powf(light_color.mV[1], 2.2f);
+				light_color.mV[2] = powf(light_color.mV[2], 2.2f);*/
+			}
+
 			mHWLightColors[cur_light] = light_color;
 			LLLightState* light_state = gGL.getLight(cur_light);
 			
@@ -5912,7 +6287,7 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
 			if (sRenderDeferred)
 			{
 				F32 size = light_radius*1.5f;
-				light_state->setLinearAttenuation(size*size);
+				light_state->setLinearAttenuation(size);
 				light_state->setQuadraticAttenuation(light->getLightFalloff()*0.5f+1.f);
 			}
 			else
@@ -5975,6 +6350,13 @@ void LLPipeline::setupHWLights(LLDrawPool* pool)
 			F32 x = 3.f;
 		float linatten = x / (light_radius); // % of brightness at radius
 
+		if (LLPipeline::sRenderDeferred)
+		{
+			/*light_color.mV[0] = powf(light_color.mV[0], 2.2f);
+			light_color.mV[1] = powf(light_color.mV[1], 2.2f);
+			light_color.mV[2] = powf(light_color.mV[2], 2.2f);*/
+		}
+
 		mHWLightColors[2] = light_color;
 		LLLightState* light = gGL.getLight(2);
 
@@ -6615,20 +6997,26 @@ BOOL LLPipeline::getRenderHighlights(void*)
 	return sRenderHighlight;
 }
 
-LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start, const LLVector3& end,
+// static
+void LLPipeline::setRenderHighlightTextureChannel(LLRender::eTexIndex channel)
+{
+	sRenderHighlightTextureChannel = channel;
+}
+
+LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector4a& start, const LLVector4a& end,
 														BOOL pick_transparent,												
 														S32* face_hit,
-														LLVector3* intersection,         // return the intersection point
+														LLVector4a* intersection,         // return the intersection point
 														LLVector2* tex_coord,            // return the texture coordinates of the intersection point
-														LLVector3* normal,               // return the surface normal at the intersection point
-														LLVector3* bi_normal             // return the surface bi-normal at the intersection point
+														LLVector4a* normal,               // return the surface normal at the intersection point
+														LLVector4a* tangent             // return the surface tangent at the intersection point
 	)
 {
 	LLDrawable* drawable = NULL;
 
-	LLVector3 local_end = end;
+	LLVector4a local_end = end;
 
-	LLVector3 position;
+	LLVector4a position;
 
 	sPickAvatar = FALSE; //LLToolMgr::getInstance()->inBuildMode() ? FALSE : TRUE;
 	
@@ -6648,7 +7036,7 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start,
 				LLSpatialPartition* part = region->getSpatialPartition(j);
 				if (part && hasRenderType(part->mDrawableType))
 				{
-					LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal);
+					LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, tangent);
 					if (hit)
 					{
 						drawable = hit;
@@ -6663,8 +7051,8 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start,
 	{
 		//save hit info in case we need to restore
 		//due to attachment override
-		LLVector3 local_normal;
-		LLVector3 local_binormal;
+		LLVector4a local_normal;
+		LLVector4a local_tangent;
 		LLVector2 local_texcoord;
 		S32 local_face_hit = -1;
 
@@ -6676,14 +7064,22 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start,
 		{
 			local_texcoord = *tex_coord;
 		}
-		if (bi_normal)
+		if (tangent)
 		{
-			local_binormal = *bi_normal;
+			local_tangent = *tangent;
+		}
+		else
+		{
+			local_tangent.clear();
 		}
 		if (normal)
 		{
 			local_normal = *normal;
 		}
+		else
+		{
+			local_normal.clear();
+		}
 				
 		const F32 ATTACHMENT_OVERRIDE_DIST = 0.1f;
 
@@ -6697,12 +7093,15 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start,
 			LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_BRIDGE);
 			if (part && hasRenderType(part->mDrawableType))
 			{
-				LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal);
+				LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, tangent);
 				if (hit)
 				{
+					LLVector4a delta;
+					delta.setSub(position, local_end);
+
 					if (!drawable || 
 						!drawable->getVObj()->isAttachment() ||
-						(position-local_end).magVec() > ATTACHMENT_OVERRIDE_DIST)
+						delta.getLength3().getF32() > ATTACHMENT_OVERRIDE_DIST)
 					{ //avatar overrides if previously hit drawable is not an attachment or 
 					  //attachment is far enough away from detected intersection
 						drawable = hit;
@@ -6720,9 +7119,9 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start,
 						{
 							*tex_coord = local_texcoord;
 						}
-						if (bi_normal)
+						if (tangent)
 						{
-							*bi_normal = local_binormal;
+							*tangent = local_tangent;
 						}
 						if (normal)
 						{
@@ -6756,13 +7155,13 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start,
 	return drawable ? drawable->getVObj().get() : NULL;
 }
 
-LLViewerObject* LLPipeline::lineSegmentIntersectInHUD(const LLVector3& start, const LLVector3& end,
+LLViewerObject* LLPipeline::lineSegmentIntersectInHUD(const LLVector4a& start, const LLVector4a& end,
 													  BOOL pick_transparent,													
 													  S32* face_hit,
-													  LLVector3* intersection,         // return the intersection point
+													  LLVector4a* intersection,         // return the intersection point
 													  LLVector2* tex_coord,            // return the texture coordinates of the intersection point
-													  LLVector3* normal,               // return the surface normal at the intersection point
-													  LLVector3* bi_normal             // return the surface bi-normal at the intersection point
+													  LLVector4a* normal,               // return the surface normal at the intersection point
+													  LLVector4a* tangent				// return the surface tangent at the intersection point
 	)
 {
 	LLDrawable* drawable = NULL;
@@ -6782,7 +7181,7 @@ LLViewerObject* LLPipeline::lineSegmentIntersectInHUD(const LLVector3& start, co
 		LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_HUD);
 		if (part)
 		{
-			LLDrawable* hit = part->lineSegmentIntersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, bi_normal);
+			LLDrawable* hit = part->lineSegmentIntersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, tangent);
 			if (hit)
 			{
 				drawable = hit;
@@ -6886,7 +7285,9 @@ void LLPipeline::doResetVertexBuffers()
 
 	LLVertexBuffer::unbind();	
 	
-	sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
+	updateRenderBump();
+	updateRenderDeferred();
+
 	sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
 	LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
 	LLVertexBuffer::sUseVAO = gSavedSettings.getBOOL("RenderUseVAO");
@@ -6912,6 +7313,17 @@ void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture, BOOL batch_text
 	gGLLastMatrix = NULL;		
 }
 
+void LLPipeline::renderMaskedObjects(U32 type, U32 mask, BOOL texture, BOOL batch_texture)
+{
+	assertInitialized();
+	gGL.loadMatrix(gGLModelView);
+	gGLLastMatrix = NULL;
+	mAlphaMaskPool->pushMaskBatches(type, mask, texture, batch_texture);
+	gGL.loadMatrix(gGLModelView);
+	gGLLastMatrix = NULL;		
+}
+
+
 void apply_cube_face_rotation(U32 face)
 {
 	switch (face)
@@ -7013,10 +7425,10 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
 	gGL.loadIdentity();
 
 	LLGLDisable test(GL_ALPHA_TEST);
-
+	
 	gGL.setColorMask(true, true);
 	glClearColor(0,0,0,0);
-		
+	
 	{
 		{
 			LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
@@ -7188,13 +7600,18 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
 			{
 				if (LLViewerJoystick::getInstance()->getOverrideCamera())
 				{ //focus on point under cursor
-					focus_point = gDebugRaycastIntersection;
+					focus_point.set(gDebugRaycastIntersection.getF32ptr());
 				}
 				else if (gAgentCamera.cameraMouselook())
 				{ //focus on point under mouselook crosshairs
+					LLVector4a result;
+					result.clear();
+
 					gViewerWindow->cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE,
 													NULL,
-													&focus_point);
+													&result);
+
+					focus_point.set(result.getF32ptr());
 				}
 				else
 				{
@@ -7354,6 +7771,13 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
 					mScreen.bindTexture(0, channel);
 					gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
 				}
+				
+				if (!LLViewerCamera::getInstance()->cameraUnderWater())
+				{
+					shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 2.2);
+				} else {
+					shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 1.0);
+				}
 
 				shader->uniform1f(LLShaderMgr::DOF_MAX_COF, CameraMaxCoF);
 				shader->uniform1f(LLShaderMgr::DOF_RES_SCALE, CameraDoFResScale);
@@ -7395,6 +7819,13 @@ void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
 			{
 				mScreen.bindTexture(0, channel);
 			}
+			
+			if (!LLViewerCamera::getInstance()->cameraUnderWater())
+			{
+				shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 2.2);
+			} else {
+				shader->uniform1f(LLShaderMgr::GLOBAL_GAMMA, 1.0);
+			}
 
 			gGL.begin(LLRender::TRIANGLE_STRIP);
 			gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
@@ -7815,6 +8246,22 @@ void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, U32 n
 	}
 }
 
+LLColor3 pow3f(LLColor3 v, F32 f)
+{
+	v.mV[0] = powf(v.mV[0], f);
+	v.mV[1] = powf(v.mV[1], f);
+	v.mV[2] = powf(v.mV[2], f);
+	return v;
+}
+
+LLVector4 pow4fsrgb(LLVector4 v, F32 f)
+{
+	v.mV[0] = powf(v.mV[0], f);
+	v.mV[1] = powf(v.mV[1], f);
+	v.mV[2] = powf(v.mV[2], f);
+	return v;
+}
+
 static LLFastTimer::DeclareTimer FTM_GI_TRACE("Trace");
 static LLFastTimer::DeclareTimer FTM_GI_GATHER("Gather");
 static LLFastTimer::DeclareTimer FTM_SUN_SHADOW("Shadow Map");
@@ -7868,11 +8315,7 @@ void LLPipeline::renderDeferredLighting()
 
 		LLStrider<LLVector3> vert; 
 		mDeferredVB->getVertexStrider(vert);
-		LLStrider<LLVector2> tc0;
-		LLStrider<LLVector2> tc1;
-		mDeferredVB->getTexCoord0Strider(tc0);
-		mDeferredVB->getTexCoord1Strider(tc1);
-
+		
 		vert[0].set(-1,1,0);
 		vert[1].set(-1,-3,0);
 		vert[2].set(3,1,0);
@@ -8053,7 +8496,7 @@ void LLPipeline::renderDeferredLighting()
 										LLPipeline::END_RENDER_TYPES);
 								
 			
-			renderGeomPostDeferred(*LLViewerCamera::getInstance());
+			renderGeomPostDeferred(*LLViewerCamera::getInstance(), false);
 			gPipeline.popRenderTypeMask();
 		}
 
@@ -8147,9 +8590,13 @@ void LLPipeline::renderDeferredLighting()
 								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*s);
+							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();
@@ -8170,7 +8617,7 @@ void LLPipeline::renderDeferredLighting()
 						glh::vec3f tc(c);
 						mat.mult_matrix_vec(tc);
 					
-						fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s*s));
+						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));
 					}
 				}
@@ -8203,9 +8650,12 @@ void LLPipeline::renderDeferredLighting()
 					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*s);
+					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();
@@ -8251,9 +8701,13 @@ void LLPipeline::renderDeferredLighting()
 					fullscreen_lights.pop_front();
 					col[count] = light_colors.front();
 					light_colors.pop_front();
-
-					far_z = llmin(light[count].mV[2]-sqrtf(light[count].mV[3]), far_z);
-
+					
+					/*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())
 					{
@@ -8295,8 +8749,12 @@ void LLPipeline::renderDeferredLighting()
 
 					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*s);
+					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);
@@ -8314,6 +8772,65 @@ void LLPipeline::renderDeferredLighting()
 		gGL.setColorMask(true, true);
 	}
 
+	mScreen.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) mScreen.getWidth()*2,
+				  (F32) mScreen.getHeight()*2);
+
+		mScreen.bindTarget();
+		// Apply gamma correction to the frame here.
+		gDeferredPostGammaCorrectProgram.bind();
+		//mDeferredVB->setBuffer(LLVertexBuffer::MAP_VERTEX);
+		S32 channel = 0;
+		channel = gDeferredPostGammaCorrectProgram.enableTexture(LLShaderMgr::DEFERRED_DIFFUSE, mScreen.getUsage());
+		if (channel > -1)
+		{
+			mScreen.bindTexture(0,channel);
+			gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+		}
+		
+		gDeferredPostGammaCorrectProgram.uniform2f(LLShaderMgr::DEFERRED_SCREEN_RES, mScreen.getWidth(), mScreen.getHeight());
+		
+		F32 gamma = 1.0/2.2;
+
+		gDeferredPostGammaCorrectProgram.uniform1f(LLShaderMgr::TEXTURE_GAMMA, gamma);
+		
+		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(mScreen.getUsage());
+		gDeferredPostGammaCorrectProgram.unbind();
+		mScreen.flush();
+	}
+
+	gGL.matrixMode(LLRender::MM_PROJECTION);
+	gGL.popMatrix();
+	gGL.matrixMode(LLRender::MM_MODELVIEW);
+	gGL.popMatrix();	
+
+	mScreen.bindTarget();
+
 	{ //render non-deferred geometry (alpha, fullbright, glow)
 		LLGLDisable blend(GL_BLEND);
 		LLGLDisable stencil(GL_STENCIL_TEST);
@@ -8338,6 +8855,8 @@ void LLPipeline::renderDeferredLighting()
 						 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());
@@ -8890,19 +9409,36 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 		LLRenderPass::PASS_FULLBRIGHT, 
 		LLRenderPass::PASS_SHINY, 
 		LLRenderPass::PASS_BUMP, 
-		LLRenderPass::PASS_FULLBRIGHT_SHINY 
+		LLRenderPass::PASS_FULLBRIGHT_SHINY ,
+		LLRenderPass::PASS_MATERIAL,
+		LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE,
+		LLRenderPass::PASS_SPECMAP,
+		LLRenderPass::PASS_SPECMAP_EMISSIVE,
+		LLRenderPass::PASS_NORMMAP,
+		LLRenderPass::PASS_NORMMAP_EMISSIVE,
+		LLRenderPass::PASS_NORMSPEC,
+		LLRenderPass::PASS_NORMSPEC_EMISSIVE,
 	};
 
 	LLGLEnable cull(GL_CULL_FACE);
 
+	//enable depth clamping if available
+	LLGLEnable depth_clamp(gGLManager.mHasDepthClamp ? GL_DEPTH_CLAMP : 0);
+
 	if (use_shader)
 	{
 		gDeferredShadowCubeProgram.bind();
 	}
 
+	LLRenderTarget& occlusion_target = mShadowOcclusion[LLViewerCamera::sCurCameraID-1];
+
+	occlusion_target.bindTarget();
 	updateCull(shadow_cam, result);
+	occlusion_target.flush();
+
 	stateSort(shadow_cam, result);
 	
+	
 	//generate shadow map
 	gGL.matrixMode(LLRender::MM_PROJECTION);
 	gGL.pushMatrix();
@@ -8961,7 +9497,6 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 	{
 		LLFastTimer ftm(FTM_SHADOW_ALPHA);
 		gDeferredShadowAlphaMaskProgram.bind();
-		gDeferredShadowAlphaMaskProgram.setMinimumAlpha(0.598f);
 		gDeferredShadowAlphaMaskProgram.uniform1f(LLShaderMgr::DEFERRED_SHADOW_TARGET_WIDTH, (float)target_width);
 
 		U32 mask =	LLVertexBuffer::MAP_VERTEX | 
@@ -8969,10 +9504,19 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 					LLVertexBuffer::MAP_COLOR | 
 					LLVertexBuffer::MAP_TEXTURE_INDEX;
 
-		renderObjects(LLRenderPass::PASS_ALPHA_MASK, mask, TRUE, TRUE);
-		renderObjects(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, mask, TRUE, TRUE);
+		renderMaskedObjects(LLRenderPass::PASS_ALPHA_MASK, mask, TRUE, TRUE);
+		renderMaskedObjects(LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK, mask, TRUE, TRUE);
+		gDeferredShadowAlphaMaskProgram.setMinimumAlpha(0.598f);
 		renderObjects(LLRenderPass::PASS_ALPHA, mask, TRUE, TRUE);
+
+		mask = mask & ~LLVertexBuffer::MAP_TEXTURE_INDEX;
+
 		gDeferredTreeShadowProgram.bind();
+		renderMaskedObjects(LLRenderPass::PASS_NORMSPEC_MASK, mask);
+		renderMaskedObjects(LLRenderPass::PASS_MATERIAL_ALPHA_MASK, mask);
+		renderMaskedObjects(LLRenderPass::PASS_SPECMAP_MASK, mask);
+		renderMaskedObjects(LLRenderPass::PASS_NORMMAP_MASK, mask);
+		
 		gDeferredTreeShadowProgram.setMinimumAlpha(0.598f);
 		renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE);
 	}
@@ -8982,7 +9526,10 @@ void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera
 	gDeferredShadowCubeProgram.bind();
 	gGLLastMatrix = NULL;
 	gGL.loadMatrix(gGLModelView);
-	doOcclusion(shadow_cam);
+
+	LLRenderTarget& occlusion_source = mShadow[LLViewerCamera::sCurCameraID-1];
+
+	doOcclusion(shadow_cam, occlusion_source, occlusion_target);
 
 	if (use_shader)
 	{
@@ -9303,6 +9850,22 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 					LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
 					LLPipeline::RENDER_TYPE_PASS_SHINY,
 					LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
+					LLPipeline::RENDER_TYPE_PASS_MATERIAL,
+					LLPipeline::RENDER_TYPE_PASS_MATERIAL_ALPHA,
+					LLPipeline::RENDER_TYPE_PASS_MATERIAL_ALPHA_MASK,
+					LLPipeline::RENDER_TYPE_PASS_MATERIAL_ALPHA_EMISSIVE,
+					LLPipeline::RENDER_TYPE_PASS_SPECMAP,
+					LLPipeline::RENDER_TYPE_PASS_SPECMAP_BLEND,
+					LLPipeline::RENDER_TYPE_PASS_SPECMAP_MASK,
+					LLPipeline::RENDER_TYPE_PASS_SPECMAP_EMISSIVE,
+					LLPipeline::RENDER_TYPE_PASS_NORMMAP,
+					LLPipeline::RENDER_TYPE_PASS_NORMMAP_BLEND,
+					LLPipeline::RENDER_TYPE_PASS_NORMMAP_MASK,
+					LLPipeline::RENDER_TYPE_PASS_NORMMAP_EMISSIVE,
+					LLPipeline::RENDER_TYPE_PASS_NORMSPEC,
+					LLPipeline::RENDER_TYPE_PASS_NORMSPEC_BLEND,
+					LLPipeline::RENDER_TYPE_PASS_NORMSPEC_MASK,
+					LLPipeline::RENDER_TYPE_PASS_NORMSPEC_EMISSIVE,
 					END_RENDER_TYPES);
 
 	gGL.setColorMask(false, false);
@@ -9822,7 +10385,6 @@ void LLPipeline::generateSunShadow(LLCamera& camera)
 			{
 				static LLCullResult result[4];
 
-				//LLGLEnable enable(GL_DEPTH_CLAMP_NV);
 				renderShadow(view[j], proj[j], shadow_cam, result[j], TRUE, TRUE, target_width);
 			}
 
@@ -10129,11 +10691,13 @@ void LLPipeline::generateImpostor(LLVOAvatar* avatar)
 		LLVector4a left;
 		left.load3(camera.getLeftAxis().mV);
 		left.mul(left);
+		llassert(left.dot3(left).getF32() > F_APPROXIMATELY_ZERO);
 		left.normalize3fast();
 
 		LLVector4a up;
 		up.load3(camera.getUpAxis().mV);
 		up.mul(up);
+		llassert(up.dot3(up).getF32() > F_APPROXIMATELY_ZERO);
 		up.normalize3fast();
 
 		tdim.mV[0] = fabsf(half_height.dot3(left).getF32());
diff --git a/indra/newview/pipeline.h b/indra/newview/pipeline.h
index a8db93585e66aa8c22ae37f8446e32dcd3629ec0..70dcf8040708568ae3c576bb686a814a137c635c 100755
--- a/indra/newview/pipeline.h
+++ b/indra/newview/pipeline.h
@@ -35,7 +35,8 @@
 #include "llspatialpartition.h"
 #include "m4math.h"
 #include "llpointer.h"
-#include "lldrawpool.h"
+#include "lldrawpoolalpha.h"
+#include "lldrawpoolmaterials.h"
 #include "llgl.h"
 #include "lldrawable.h"
 #include "llrendertarget.h"
@@ -59,6 +60,7 @@ class LLCullResult;
 class LLVOAvatar;
 class LLGLSLShader;
 class LLCurlRequest;
+class LLDrawPoolAlpha;
 
 class LLMeshResponder;
 
@@ -95,6 +97,7 @@ extern LLFastTimer::DeclareTimer FTM_RENDER_WL_SKY;
 extern LLFastTimer::DeclareTimer FTM_RENDER_ALPHA;
 extern LLFastTimer::DeclareTimer FTM_RENDER_CHARACTERS;
 extern LLFastTimer::DeclareTimer FTM_RENDER_BUMP;
+extern LLFastTimer::DeclareTimer FTM_RENDER_MATERIALS;
 extern LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT;
 extern LLFastTimer::DeclareTimer FTM_RENDER_GLOW;
 extern LLFastTimer::DeclareTimer FTM_STATESORT;
@@ -173,6 +176,12 @@ class LLPipeline
 	// Object related methods
 	void        markVisible(LLDrawable *drawablep, LLCamera& camera);
 	void		markOccluder(LLSpatialGroup* group);
+
+	//downsample source to dest, taking the maximum depth value per pixel in source and writing to dest
+	// if source's depth buffer cannot be bound for reading, a scratch space depth buffer must be provided
+	void		downsampleDepthBuffer(LLRenderTarget& source, LLRenderTarget& dest, LLRenderTarget* scratch_space = NULL);
+
+	void		doOcclusion(LLCamera& camera, LLRenderTarget& source, LLRenderTarget& dest, LLRenderTarget* scratch_space = NULL);
 	void		doOcclusion(LLCamera& camera);
 	void		markNotCulled(LLSpatialGroup* group, LLCamera &camera);
 	void        markMoved(LLDrawable *drawablep, BOOL damped_motion = FALSE);
@@ -185,21 +194,21 @@ class LLPipeline
 	void		markMeshDirty(LLSpatialGroup* group);
 
 	//get the object between start and end that's closest to start.
-	LLViewerObject* lineSegmentIntersectInWorld(const LLVector3& start, const LLVector3& end,
+	LLViewerObject* lineSegmentIntersectInWorld(const LLVector4a& start, const LLVector4a& end,
 												BOOL pick_transparent,
 												S32* face_hit,                          // return the face hit
-												LLVector3* intersection = NULL,         // return the intersection point
+												LLVector4a* intersection = NULL,         // return the intersection point
 												LLVector2* tex_coord = NULL,            // return the texture coordinates of the intersection point
-												LLVector3* normal = NULL,               // return the surface normal at the intersection point
-												LLVector3* bi_normal = NULL             // return the surface bi-normal at the intersection point  
+												LLVector4a* normal = NULL,               // return the surface normal at the intersection point
+												LLVector4a* tangent = NULL             // return the surface tangent at the intersection point  
 		);
-	LLViewerObject* lineSegmentIntersectInHUD(const LLVector3& start, const LLVector3& end,
+	LLViewerObject* lineSegmentIntersectInHUD(const LLVector4a& start, const LLVector4a& end,
 											  BOOL pick_transparent,
 											  S32* face_hit,                          // return the face hit
-											  LLVector3* intersection = NULL,         // return the intersection point
+											  LLVector4a* intersection = NULL,         // return the intersection point
 											  LLVector2* tex_coord = NULL,            // return the texture coordinates of the intersection point
-											  LLVector3* normal = NULL,               // return the surface normal at the intersection point
-											  LLVector3* bi_normal = NULL             // return the surface bi-normal at the intersection point
+											  LLVector4a* normal = NULL,               // return the surface normal at the intersection point
+											  LLVector4a* tangent = NULL             // return the surface tangent at the intersection point
 		);
 
 	// Something about these textures has changed.  Dirty them.
@@ -256,6 +265,8 @@ class LLPipeline
 	void forAllVisibleDrawables(void (*func)(LLDrawable*));
 
 	void renderObjects(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_texture = FALSE);
+	void renderMaskedObjects(U32 type, U32 mask, BOOL texture = TRUE, BOOL batch_texture = FALSE);
+
 	void renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture);
 
 	void grabReferences(LLCullResult& result);
@@ -270,7 +281,7 @@ class LLPipeline
 
 	void renderGeom(LLCamera& camera, BOOL forceVBOUpdate = FALSE);
 	void renderGeomDeferred(LLCamera& camera);
-	void renderGeomPostDeferred(LLCamera& camera);
+	void renderGeomPostDeferred(LLCamera& camera, bool do_occlusion=true);
 	void renderGeomShadow(LLCamera& camera);
 	void bindDeferredShader(LLGLSLShader& shader, U32 light_index = 0, U32 noise_map = 0xFFFFFFFF);
 	void setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep);
@@ -389,12 +400,16 @@ class LLPipeline
 	static void setRenderHighlights(BOOL val);
 	static void toggleRenderHighlights(void* data);
 	static BOOL getRenderHighlights(void* data);
+	static void setRenderHighlightTextureChannel(LLRender::eTexIndex channel); // sets which UV setup to display in highlight overlay
 
+	static void updateRenderBump();
 	static void updateRenderDeferred();
 	static void refreshCachedSettings();
 
 	static void throttleNewMemoryAllocation(BOOL disable);
 
+	
+
 	void addDebugBlip(const LLVector3& position, const LLColor4& color);
 
 	void hidePermanentObjects( std::vector<U32>& restoreList );
@@ -425,8 +440,11 @@ class LLPipeline
 		RENDER_TYPE_TERRAIN						= LLDrawPool::POOL_TERRAIN,
 		RENDER_TYPE_SIMPLE						= LLDrawPool::POOL_SIMPLE,
 		RENDER_TYPE_GRASS						= LLDrawPool::POOL_GRASS,
+		RENDER_TYPE_ALPHA_MASK					= LLDrawPool::POOL_ALPHA_MASK,
+		RENDER_TYPE_FULLBRIGHT_ALPHA_MASK		= LLDrawPool::POOL_FULLBRIGHT_ALPHA_MASK,
 		RENDER_TYPE_FULLBRIGHT					= LLDrawPool::POOL_FULLBRIGHT,
 		RENDER_TYPE_BUMP						= LLDrawPool::POOL_BUMP,
+		RENDER_TYPE_MATERIALS					= LLDrawPool::POOL_MATERIALS,
 		RENDER_TYPE_AVATAR						= LLDrawPool::POOL_AVATAR,
 		RENDER_TYPE_TREE						= LLDrawPool::POOL_TREE,
 		RENDER_TYPE_INVISIBLE					= LLDrawPool::POOL_INVISIBLE,
@@ -447,6 +465,22 @@ class LLPipeline
 		RENDER_TYPE_PASS_ALPHA					= LLRenderPass::PASS_ALPHA,
 		RENDER_TYPE_PASS_ALPHA_MASK				= LLRenderPass::PASS_ALPHA_MASK,
 		RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK	= LLRenderPass::PASS_FULLBRIGHT_ALPHA_MASK,
+		RENDER_TYPE_PASS_MATERIAL				= LLRenderPass::PASS_MATERIAL,
+		RENDER_TYPE_PASS_MATERIAL_ALPHA			= LLRenderPass::PASS_MATERIAL_ALPHA,
+		RENDER_TYPE_PASS_MATERIAL_ALPHA_MASK	= LLRenderPass::PASS_MATERIAL_ALPHA_MASK,
+		RENDER_TYPE_PASS_MATERIAL_ALPHA_EMISSIVE= LLRenderPass::PASS_MATERIAL_ALPHA_EMISSIVE,
+		RENDER_TYPE_PASS_SPECMAP				= LLRenderPass::PASS_SPECMAP,
+		RENDER_TYPE_PASS_SPECMAP_BLEND			= LLRenderPass::PASS_SPECMAP_BLEND,
+		RENDER_TYPE_PASS_SPECMAP_MASK			= LLRenderPass::PASS_SPECMAP_MASK,
+		RENDER_TYPE_PASS_SPECMAP_EMISSIVE		= LLRenderPass::PASS_SPECMAP_EMISSIVE,
+		RENDER_TYPE_PASS_NORMMAP				= LLRenderPass::PASS_NORMMAP,
+		RENDER_TYPE_PASS_NORMMAP_BLEND			= LLRenderPass::PASS_NORMMAP_BLEND,
+		RENDER_TYPE_PASS_NORMMAP_MASK			= LLRenderPass::PASS_NORMMAP_MASK,
+		RENDER_TYPE_PASS_NORMMAP_EMISSIVE		= LLRenderPass::PASS_NORMMAP_EMISSIVE,
+		RENDER_TYPE_PASS_NORMSPEC				= LLRenderPass::PASS_NORMSPEC,
+		RENDER_TYPE_PASS_NORMSPEC_BLEND			= LLRenderPass::PASS_NORMSPEC_BLEND,
+		RENDER_TYPE_PASS_NORMSPEC_MASK			= LLRenderPass::PASS_NORMSPEC_MASK,
+		RENDER_TYPE_PASS_NORMSPEC_EMISSIVE		= LLRenderPass::PASS_NORMSPEC_EMISSIVE,
 		// Following are object types (only used in drawable mRenderType)
 		RENDER_TYPE_HUD = LLRenderPass::NUM_RENDER_TYPES,
 		RENDER_TYPE_VOLUME,
@@ -562,7 +596,8 @@ class LLPipeline
 	static BOOL				sRenderDeferred;
 	static BOOL             sMemAllocationThrottled;
 	static S32				sVisibleLightCount;
-	static F32				sMinRenderSize;	
+	static F32				sMinRenderSize;
+	static BOOL				sRenderingHUDs;
 
 	//screen texture
 	U32 					mScreenWidth;
@@ -574,6 +609,7 @@ class LLPipeline
 	LLRenderTarget			mFXAABuffer;
 	LLRenderTarget			mEdgeMap;
 	LLRenderTarget			mDeferredDepth;
+	LLRenderTarget			mOcclusionDepth;
 	LLRenderTarget			mDeferredLight;
 	LLRenderTarget			mHighlight;
 	LLRenderTarget			mPhysicsDisplay;
@@ -586,6 +622,7 @@ class LLPipeline
 
 	//sun shadow map
 	LLRenderTarget			mShadow[6];
+	LLRenderTarget			mShadowOcclusion[6];
 	std::vector<LLVector3>	mShadowFrustPoints[4];
 	LLVector4				mShadowError;
 	LLVector4				mShadowFOV;
@@ -773,17 +810,20 @@ class LLPipeline
 	// For quick-lookups into mPools (mapped by texture pointer)
 	std::map<uintptr_t, LLDrawPool*>	mTerrainPools;
 	std::map<uintptr_t, LLDrawPool*>	mTreePools;
-	LLDrawPool*					mAlphaPool;
+	LLDrawPoolAlpha*			mAlphaPool;
 	LLDrawPool*					mSkyPool;
 	LLDrawPool*					mTerrainPool;
 	LLDrawPool*					mWaterPool;
 	LLDrawPool*					mGroundPool;
 	LLRenderPass*				mSimplePool;
 	LLRenderPass*				mGrassPool;
+	LLRenderPass*				mAlphaMaskPool;
+	LLRenderPass*				mFullbrightAlphaMaskPool;
 	LLRenderPass*				mFullbrightPool;
 	LLDrawPool*					mInvisiblePool;
 	LLDrawPool*					mGlowPool;
 	LLDrawPool*					mBumpPool;
+	LLDrawPool*					mMaterialsPool;
 	LLDrawPool*					mWLSkyPool;
 	// Note: no need to keep an quick-lookup to avatar pools, since there's only one per avatar
 	
@@ -822,6 +862,10 @@ class LLPipeline
 	static BOOL				sRenderBeacons;
 	static BOOL				sRenderHighlight;
 
+	// Determines which set of UVs to use in highlight display
+	//
+	static LLRender::eTexIndex sRenderHighlightTextureChannel;
+
 	//debug use
 	static U32              sCurRenderPoolType ;
 
diff --git a/indra/newview/skins/default/colors.xml b/indra/newview/skins/default/colors.xml
index 42568775d91fab258cb3b1231d7b5e2ed0e1a5e6..a9176595c7c0df87623b9344d8c7f6b960edc048 100755
--- a/indra/newview/skins/default/colors.xml
+++ b/indra/newview/skins/default/colors.xml
@@ -656,6 +656,15 @@
   <color
       name="PathfindingGoodColor"
       reference="LtGreen" />
+  <color
+      name="MaterialErrorColor"
+      reference="LtRed" />
+  <color
+      name="MaterialWarningColor"
+      reference="DrYellow" />
+  <color
+      name="MaterialGoodColor"
+      reference="LtGreen" />
   <color
       name="PathfindingDefaultBeaconColor"
       reference="Red_80" />
diff --git a/indra/newview/skins/default/textures/flatnormal.tga b/indra/newview/skins/default/textures/flatnormal.tga
new file mode 100644
index 0000000000000000000000000000000000000000..6d5abd17821b5589422617c7e5665a93def5a48a
Binary files /dev/null and b/indra/newview/skins/default/textures/flatnormal.tga differ
diff --git a/indra/newview/skins/default/textures/materials_ui_x_24.png b/indra/newview/skins/default/textures/materials_ui_x_24.png
new file mode 100644
index 0000000000000000000000000000000000000000..6d8855491483301b3de7e279d9d1b1f870f34246
Binary files /dev/null and b/indra/newview/skins/default/textures/materials_ui_x_24.png differ
diff --git a/indra/newview/skins/default/textures/textures.xml b/indra/newview/skins/default/textures/textures.xml
index fcab966dee78df48b26057a4b3457de3a6dc4ad8..b0e4b71d21554f3672ed08ceb70dc652c4b0cd5b 100755
--- a/indra/newview/skins/default/textures/textures.xml
+++ b/indra/newview/skins/default/textures/textures.xml
@@ -743,6 +743,7 @@ with the same filename but different name
   <texture name="default_land_picture.j2c" />
   <texture name="default_profile_picture.j2c" />
   <texture name="locked_image.j2c" />
+  <texture name="materials_ui_x_24.png" />
 
   <texture name="Progress_1" file_name="icons/Progress_1.png" preload="true" />
   <texture name="Progress_2" file_name="icons/Progress_2.png" preload="true" />
diff --git a/indra/newview/skins/default/xui/da/menu_viewer.xml b/indra/newview/skins/default/xui/da/menu_viewer.xml
index d695cd1f896c446899361f744610017d054bba3f..f2ed7c2e64cf19dac5530625dece1f272c4b2c6f 100755
--- a/indra/newview/skins/default/xui/da/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/da/menu_viewer.xml
@@ -245,7 +245,7 @@
 		<menu label="Gengivelse" name="Rendering">
 			<menu_item_check label="Akser" name="Axes"/>
 			<menu_item_check label="Wireframe" name="Wireframe"/>
-			<menu_item_check label="Lys og skygger" name="Lighting and Shadows"/>
+			<menu_item_check label="Lys og skygger" name="Advanced Lighting Model"/>
 			<menu_item_check label="Skygger fra sol/måne/andre lyskilder" name="Shadows from Sun/Moon/Projectors"/>
 			<menu_item_check label="SSAO og skygge udjævning" name="SSAO and Shadow Smoothing"/>
 			<menu_item_check label="Globalt lys (eksperimentiel)" name="Global Illumination"/>
diff --git a/indra/newview/skins/default/xui/de/menu_viewer.xml b/indra/newview/skins/default/xui/de/menu_viewer.xml
index 2c9d9fa7f12bbc627707c0003168d79ccdf94ad3..47d9fec35276a4c25c6710782db1b0a8005bdc9e 100755
--- a/indra/newview/skins/default/xui/de/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/de/menu_viewer.xml
@@ -315,7 +315,7 @@
 			<menu_item_call label="Texturinfo für ausgewähltes Objekt" name="Selected Texture Info Basis"/>
 			<menu_item_check label="Wireframe" name="Wireframe"/>
 			<menu_item_check label="Objekt-Objekt Okklusion" name="Object-Object Occlusion"/>
-			<menu_item_check label="Licht und Schatten" name="Lighting and Shadows"/>
+			<menu_item_check label="Uber Licht Modell" name="Advanced Lighting Model"/>
 			<menu_item_check label="Schatten von Sonne-/Mond-Projektoren" name="Shadows from Sun/Moon/Projectors"/>
 			<menu_item_check label="SSAO und Schattenglättung" name="SSAO and Shadow Smoothing"/>
 			<menu_item_check label="Fehler in GL beseitigen" name="Debug GL"/>
@@ -393,14 +393,9 @@
 				<menu_item_call label="Weiblich testen" name="Test Female"/>
 				<menu_item_check label="Avatarauswahl zulassen" name="Allow Select Avatar"/>
 			</menu>
-			<menu label="Animationsgeschwindigkeit" name="Animation Speed">
-				<menu_item_call label="Alle Animationen 10 % schneller" name="All Animations 10 Faster"/>
-				<menu_item_call label="Alle Animationen 10 % langsamer" name="All Animations 10 Slower"/>
-				<menu_item_call label="Alle Animationsgeschwindigkeiten zurücksetzen" name="Reset All Animation Speed"/>
-				<menu_item_check label="Zeitlupen-Animationen" name="Slow Motion Animations"/>
-			</menu>
 			<menu_item_call label="Param auf Standard erzwingen" name="Force Params to Default"/>
 			<menu_item_check label="Animations-Info" name="Animation Info"/>
+			<menu_item_check label="Zeitlupen-Animationen" name="Slow Motion Animations"/>
 			<menu_item_check label="Kamerafokus anzeigen" name="Show Look At"/>
 			<menu_item_check label="Klickpunkt anzeigen??" name="Show Point At"/>
 			<menu_item_check label="Fehler in Landaktualisierung beseitigen" name="Debug Joint Updates"/>
diff --git a/indra/newview/skins/default/xui/en/floater_tools.xml b/indra/newview/skins/default/xui/en/floater_tools.xml
index 436e9f8fed65dfbfa6af5aa751c4c227d8e9400f..8b9733df17a438b6562ddf7ad0702f34c6d9a198 100755
--- a/indra/newview/skins/default/xui/en/floater_tools.xml
+++ b/indra/newview/skins/default/xui/en/floater_tools.xml
@@ -2491,534 +2491,10 @@ even though the user gets a free copy.
              width="132" />
         </panel>
          <panel
-         border="false"
-         follows="all"
-         height="367"
          label="Texture"
-         layout="topleft"
-         left_delta="0"
-         mouse_opaque="false"
          help_topic="toolbox_texture_tab"
          name="Texture"
-         top_delta="0"
-         width="295">
-            <panel.string
-             name="string repeats per meter">
-                Repeats Per Meter
-            </panel.string>
-            <panel.string
-             name="string repeats per face">
-                Repeats Per Face
-            </panel.string>
-            <texture_picker
-             can_apply_immediately="true"
-             default_image_name="Default"
-             fallback_image="locked_image.j2c"
-             follows="left|top"
-             height="80"
-             label="Texture"
-             layout="topleft"
-             left="10"
-             name="texture control"
-             tool_tip="Click to choose a picture"
-             top="8"
-             width="64" />
-            <color_swatch
-             can_apply_immediately="true"
-             follows="left|top"
-             height="80"
-             label="Color"
-             layout="topleft"
-             left_pad="15"
-             name="colorswatch"
-             tool_tip="Click to open color picker"
-             top_delta="0"
-             width="64" />
-            <text
-             type="string"
-             length="1"
-             follows="left|top"
-             height="10"
-             layout="topleft"
-             left_pad="15"
-             name="color trans"
-             text_readonly_color="LabelDisabledColor"
-             top="6"
-             width="110">
-                Transparency %
-            </text>
-            <spinner
-             decimal_digits="0"
-             follows="left|top"
-             height="19"
-             increment="2"
-             initial_value="0"
-             layout="topleft"
-             left_delta="0"
-             max_val="100"
-             name="ColorTrans"
-             top_pad="4"
-             width="80" />
-            <text
-             type="string"
-             length="1"
-             follows="left|top"
-             height="10"
-             layout="topleft"
-             left_delta="0"
-             name="glow label"
-             text_readonly_color="LabelDisabledColor"
-             top_pad="8"
-             width="80">
-                Glow
-            </text>
-            <spinner
-             decimal_digits="2"
-             follows="left|top"
-             height="19"
-             initial_value="0"
-             layout="topleft"
-             left_delta="0"
-             name="glow"
-             top_pad="4"
-             width="80" />
-            <check_box
-             height="19"
-             label="Full Bright"
-             layout="topleft"
-             left_delta="-5"
-             name="checkbox fullbright"
-             top_pad="4"
-             width="81" />
-            <text
-             type="string"
-             length="1"
-             follows="left|top"
-             height="10"
-             layout="topleft"
-             left="10"
-             name="tex gen"
-             text_readonly_color="LabelDisabledColor"
-             top_pad="5"
-             width="90">
-                Mapping
-            </text>
-            <combo_box
-             height="23"
-             layout="topleft"
-             left_delta="0"
-             name="combobox texgen"
-             top_pad="4"
-             width="90">
-                <combo_box.item
-                 label="Default"
-                 name="Default"
-                 value="Default" />
-                <combo_box.item
-                 label="Planar"
-                 name="Planar"
-                 value="Planar" />
-            </combo_box>
-            <text
-             type="string"
-             length="1"
-             follows="left|top"
-             height="10"
-             layout="topleft"
-             name="label shininess"
-             left_pad="4"
-             text_readonly_color="LabelDisabledColor"
-             top_pad="-37"
-             width="90">
-                Shininess
-            </text>
-            <combo_box
-             height="23"
-             layout="topleft"
-             left_delta="0"
-             name="combobox shininess"
-             top_pad="4"
-             width="90">
-                <combo_box.item
-                 label="None"
-                 name="None"
-                 value="None" />
-                <combo_box.item
-                 label="Low"
-                 name="Low"
-                 value="Low" />
-                <combo_box.item
-                 label="Medium"
-                 name="Medium"
-                 value="Medium" />
-                <combo_box.item
-                 label="High"
-                 name="High"
-                 value="High" />
-            </combo_box>
-            <text
-             type="string"
-             length="1"
-             follows="left|top"
-             height="10"
-             layout="topleft"
-             left_pad="4"
-             name="label bumpiness"
-             text_readonly_color="LabelDisabledColor"
-             top_pad="-37"
-             width="90">
-                Bumpiness
-            </text>
-            <combo_box
-             height="23"
-             layout="topleft"
-             left_delta="0"
-             name="combobox bumpiness"
-             top_pad="4"
-             width="90">
-                <combo_box.item
-                 label="None"
-                 name="None"
-                 value="None" />
-                <combo_box.item
-                 label="Brightness"
-                 name="Brightness"
-                 value="Brightness" />
-                <combo_box.item
-                 label="Darkness"
-                 name="Darkness"
-                 value="Darkness" />
-                <combo_box.item
-                 label="woodgrain"
-                 name="woodgrain"
-                 value="woodgrain" />
-                <combo_box.item
-                 label="bark"
-                 name="bark"
-                 value="bark" />
-                <combo_box.item
-                 label="bricks"
-                 name="bricks"
-                 value="bricks" />
-                <combo_box.item
-                 label="checker"
-                 name="checker"
-                 value="checker" />
-                <combo_box.item
-                 label="concrete"
-                 name="concrete"
-                 value="concrete" />
-                <combo_box.item
-                 label="crustytile"
-                 name="crustytile"
-                 value="crustytile" />
-                <combo_box.item
-                 label="cutstone"
-                 name="cutstone"
-                 value="cutstone" />
-                <combo_box.item
-                 label="discs"
-                 name="discs"
-                 value="discs" />
-                <combo_box.item
-                 label="gravel"
-                 name="gravel"
-                 value="gravel" />
-                <combo_box.item
-                 label="petridish"
-                 name="petridish"
-                 value="petridish" />
-                <combo_box.item
-                 label="siding"
-                 name="siding"
-                 value="siding" />
-                <combo_box.item
-                 label="stonetile"
-                 name="stonetile"
-                 value="stonetile" />
-                <combo_box.item
-                 label="stucco"
-                 name="stucco"
-                 value="stucco" />
-                <combo_box.item
-                 label="suction"
-                 name="suction"
-                 value="suction" />
-                <combo_box.item
-                 label="weave"
-                 name="weave"
-                 value="weave" />
-            </combo_box>
-          <!--
-            <line_editor
-             bevel_style="in"
-             border_style="line"
-             border_thickness="1"
-             follows="left|top"
-             height="16"
-             layout="topleft"
-             left="10"
-             max_length_bytes="63"
-             name="Home Url"
-             select_on_focus="true"
-             top="134"
-             width="250" />
-            <check_box
-             height="16"
-             label="Media Face"
-             layout="topleft"
-             left_delta="0"
-             name="has media"
-             top_pad="6"
-             width="70" />
-            <button
-             follows="left|top"
-             font="SansSerifSmall"
-             height="20"
-             label="Set Media Info"
-             label_selected="Set Media Info"
-             layout="topleft"
-             left_pad="60"
-             name="media info set"
-             top_delta="-4"
-             width="120" />
--->
-            <check_box
-             follows="top|left"
-             height="16"
-             initial_value="false"
-             label="Align planar faces"
-             layout="topleft"
-             left="17"
-             name="checkbox planar align"
-             tool_tip="Align textures on all selected faces with the last selected face. Requires Planar texture mapping."
-             top_delta="26"
-             width="140" />
-            <text
-             type="string"
-             length="1"
-             follows="left|top"
-             height="10"
-             layout="topleft"
-             left="10"
-             name="rpt"
-             text_readonly_color="LabelDisabledColor"
-             top_pad="2"
-             width="140">
-                Repeats / Face
-            </text>
-            <spinner
-             follows="left|top"
-             height="19"
-             initial_value="0"
-             label="Horizontal (U)"
-             label_width="125"
-             layout="topleft"
-             left="20"
-             max_val="100"
-             name="TexScaleU"
-             top_pad="5"
-             width="185" />
-            <check_box
-             height="19"
-             label="Flip"
-             layout="topleft"
-             left_pad="5"
-             name="checkbox flip s"
-             top_delta="0"
-             width="70" />
-            <spinner
-             follows="left|top"
-             height="19"
-             initial_value="0"
-             label="Vertical (V)"
-             label_width="125"
-             layout="topleft"
-             left="20"
-             max_val="100"
-             name="TexScaleV"
-             width="185" />
-            <check_box
-             height="19"
-             label="Flip"
-             layout="topleft"
-             left_pad="5"
-             name="checkbox flip t"
-             top_delta="0"
-             width="70" />
-            <spinner
-             decimal_digits="2"
-             follows="left|top"
-             height="19"
-             increment="1"
-             initial_value="0"
-			 label="RotationËš"
-             layout="topleft"
-			 label_width="135"
-             left="10"
-             max_val="9999"
-             min_val="-9999"
-             name="TexRot"
-             width="195" />
-
-            <spinner
-             decimal_digits="1"
-             follows="left|top"
-             height="23"
-             initial_value="1"
-			 label="Repeats / Meter"
-             layout="topleft"
-			 label_width="135"
-             left="10"
-             max_val="10"
-             min_val="0.1"
-             name="rptctrl"
-             width="195" />
-            <button
-             follows="left|top"
-             height="23"
-             label="Apply"
-             label_selected="Apply"
-             layout="topleft"
-             left_pad="5"
-             name="button apply"
-             width="75" />
-            <text
-             type="string"
-             length="1"
-             follows="left|top"
-             height="10"
-             layout="topleft"
-             left="10"
-             name="tex offset"
-             text_readonly_color="LabelDisabledColor"
-             width="200">
-                Texture Offset
-            </text>
-            <spinner
-             follows="left|top"
-             height="19"
-             initial_value="0"
-             label="Horizontal (U)"
-             label_width="125"
-             layout="topleft"
-             left="20"
-             min_val="-1"
-             name="TexOffsetU"
-             width="185" />
-            <spinner
-             follows="left|top"
-             height="19"
-             initial_value="0"
-             label="Vertical (V)"
-             label_width="125"
-             layout="topleft"
-             left_delta="0"
-             min_val="-1"
-             name="TexOffsetV"
-             top_pad="1"
-             width="185" />
-        <panel
-         border="false"
-         follows="left|top"
-         layout="topleft"
-         mouse_opaque="false"
-         background_visible="true"
-         bg_alpha_color="DkGray"
-         name="Add_Media"
-         left="0"
-         height="47"
-         width="290">
-            <text
-             type="string"
-             length="1"
-             follows="left|top"
-             height="18"
-             layout="topleft"
-             left="10"
-             top_pad="3"
-             name="media_tex"
-             width="190">
-              Media
-			</text>
-			<button
-			 follows="top|left"
-			 height="18"
-			 image_selected="AddItem_Press"
-			 image_unselected="AddItem_Off"
-			 image_disabled="AddItem_Disabled"
-			 layout="topleft"
-			 left_pad="0"
-			 name="add_media"
-			 tab_stop="false"
-			 top_delta="0"
-			 tool_tip="Add Media"
-			 width="18">
-				<button.commit_callback
-				function="BuildTool.AddMedia"/>
-			</button>
-			<button
-			 follows="top|left"
-			 height="18"
-			 image_selected="TrashItem_Press"
-			 image_unselected="TrashItem_Off"
-			 layout="topleft"
-			 left_pad="5"
-			 name="delete_media"
-			 tool_tip="Delete this media texture"
-			 top_delta="0"
-			 width="18">
-				<button.commit_callback
-				function="BuildTool.DeleteMedia"/>
-			</button>
-			<button
-			 follows="top|left"
-			 tool_tip="Edit this Media"
-			 height="12"
-             image_disabled="Icon_Gear_Background"
-             image_selected="Icon_Gear_Press"
-             image_unselected="Icon_Gear_Foreground"
-			 layout="topleft"
-			 left_pad="10"
-			 name="edit_media"
-			 top_delta="3"
-			 width="12">
-				<button.commit_callback
-				function="BuildTool.EditMedia"/>
-			</button>
-      <text
-			 follows="left|top|right"
-			 height="9"
-			 layout="topleft"
-			 left="10"
-                         use_ellipses="true"
-			 read_only="true"
-			 name="media_info"
-			 width="180" />
-      <web_browser
-        visible="false"
-        enabled="false"
-        border_visible="true"
-        bottom_delta="0"
-        follows="top|left"
-        left="0"
-        name="title_media"
-        width="4"
-        height="4"
-        start_url="about:blank"
-        decouple_texture_size="true" />
-     <button
-			 follows="right|top"
-			 height="22"
-			 label="Align"
-			 label_selected="Align Media"
-			 layout="topleft"
-			 right="-16"
-			 name="button align"
-			 top_delta="-4"
-			 tool_tip="Align media texture (must load first)"
-			 width="80" />
-		</panel>
+         filename="panel_tools_texture.xml">
 	   </panel>
        <panel
          border="false"
diff --git a/indra/newview/skins/default/xui/en/menu_viewer.xml b/indra/newview/skins/default/xui/en/menu_viewer.xml
index a11cd13fdbb5c9c0436cad7af6524e467e5f47cc..b01c3067ff577179ba54528b9c7db7350bcf0978 100755
--- a/indra/newview/skins/default/xui/en/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/en/menu_viewer.xml
@@ -2363,6 +2363,12 @@
                 <menu_item_check.on_click
                  function="Advanced.ToggleFrameTest" />
             </menu_item_check>
+          <menu_item_call
+             label="Frame Profile"
+             name="Frame Profile">
+            <menu_item_call.on_click
+             function="Advanced.ClickRenderProfile" />
+          </menu_item_call>
         </menu>
       <menu
         create_jump_keys="true"
@@ -2658,6 +2664,13 @@
                 <menu_item_call.on_click
                  function="Advanced.SelectedTextureInfo" />
             </menu_item_call>
+            <menu_item_call
+             label="Selected Material Info"
+             name="Selected Material Info"
+             shortcut="control|alt|shift|M">
+                <menu_item_call.on_click
+                 function="Advanced.SelectedMaterialInfo" />
+            </menu_item_call>
             <menu_item_check
              label="Wireframe"
              name="Wireframe"
@@ -2684,8 +2697,8 @@
           <menu_item_separator />
 
           <menu_item_check
-                       label="Lighting and Shadows"
-                       name="Lighting and Shadows">
+                       label="Advanced Lighting Model"
+                       name="Advanced Lighting Model">
             <menu_item_check.on_check
              function="CheckControl"
              parameter="RenderDeferred" />
@@ -2792,16 +2805,6 @@
                  parameter="TextureLoadFullRes" />
             </menu_item_check>
             <menu_item_check
-             label="Texture Atlas (experimental)"
-             name="Texture Atlas">
-              <menu_item_check.on_check
-               function="CheckControl"
-               parameter="EnableTextureAtlas" />
-              <menu_item_check.on_click
-               function="ToggleControl"
-               parameter="EnableTextureAtlas" />
-            </menu_item_check>
-              <menu_item_check
              label="Render Attached Lights"
              name="Render Attached Lights">
                 <menu_item_check.on_check
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index 970a11c6c48c939e3d0371f61fa0bf4a7ccbb7bd..9e582cf0de169ca608af5b03d33dffddd1c3437f 100755
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -3454,7 +3454,7 @@ or you can install it now.
    name="DownloadBackgroundTip"
    type="notify">
 We have downloaded an update to your [APP_NAME] installation.
-Version [VERSION] [[INFO_URL] Information about this update]
+Version [VERSION] [[RELEASE_NOTES_FULL_URL] Information about this update]
     <tag>confirm</tag>
     <usetemplate
      name="okcancelbuttons"
@@ -3467,7 +3467,7 @@ Version [VERSION] [[INFO_URL] Information about this update]
  name="DownloadBackgroundDialog"
  type="alertmodal">
 We have downloaded an update to your [APP_NAME] installation.
-Version [VERSION] [[INFO_URL] Information about this update]
+Version [VERSION] [[RELEASE_NOTES_FULL_URL] Information about this update]
     <tag>confirm</tag>
     <usetemplate
      name="okcancelbuttons"
@@ -6923,9 +6923,9 @@ Do not allow access if you do not fully understand why it wants access to your a
 [FOOTERTEXT]
     </footer>
   </notification>
-	
-	<notification
-	 icon="notify.tga"
+
+  <notification
+   icon="notify.tga"
 	 name="UnknownScriptQuestion"
 	 persist="false"
 	 type="notify">
diff --git a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
index cd243d40a4e653ddd8aa3fe035a755abb6f9ad56..d7db7caf66efc65ee754638f17d96d29569d9320 100755
--- a/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
+++ b/indra/newview/skins/default/xui/en/panel_preferences_graphics1.xml
@@ -211,16 +211,19 @@
 		 name="TransparentWater"
 		 top_pad="7"
 		 width="256" />
-		<check_box
-		 control_name="RenderObjectBump"
-		 height="16"
-		 initial_value="true"
-		 label="Bump mapping and shiny"
-		 layout="topleft"
-		 left_delta="0"
-		 name="BumpShiny"
-		 top_pad="1"
-		width="256" />
+      <check_box
+       control_name="RenderObjectBump"
+       height="16"
+       initial_value="true"
+       label="Bump mapping and shiny"
+       layout="topleft"
+       left_delta="0"
+       name="BumpShiny"
+       top_pad="1"
+      width="256">
+        <check_box.commit_callback
+        function="Pref.VertexShaderEnable" />
+      </check_box>
     <check_box
 		control_name="RenderLocalLights"
 		height="16"
@@ -262,7 +265,7 @@
 		 control_name="RenderDeferred"
 		 height="16"
 		 initial_value="true"
-		 label="Lighting and Shadows"
+		 label="Advanced Lighting Model"
 		 layout="topleft"
 		 left_delta="0"
 		 name="UseLightShaders"
diff --git a/indra/newview/skins/default/xui/en/panel_tools_texture.xml b/indra/newview/skins/default/xui/en/panel_tools_texture.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5ac2ec2b206bbccc4f9e302334dd49c0826e6370
--- /dev/null
+++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml
@@ -0,0 +1,766 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+         border="false"
+         follows="all"
+         height="420"
+         label="Texture"
+         layout="topleft"
+         left="0"
+         mouse_opaque="false"
+         help_topic="toolbox_texture_tab"
+         name="Texture"
+         top="0"
+         width="295">
+            <panel.string
+             name="string repeats per meter">
+                Repeats Per Meter
+            </panel.string>
+            <panel.string
+             name="string repeats per face">
+                Repeats Per Face
+            </panel.string>
+            <text
+             type="string"
+             length="1"
+             follows="left|top"
+             height="10"
+             layout="topleft"
+             left="10"
+             name="color label"
+             text_readonly_color="LabelDisabledColor"
+             top="6"
+             width="64">
+                Color
+            </text>
+            <!-- label is blank because control places it below the box -->
+            <color_swatch
+             can_apply_immediately="true"
+             follows="left|top"
+             height="45"
+             label=""
+             layout="topleft"
+             left="10"
+             name="colorswatch"
+             tool_tip="Click to open color picker"
+             top="20"
+             width="64" />
+            <text
+             type="string"
+             length="1"
+             follows="left|top"
+             height="10"
+             layout="topleft"
+             left_pad="15"
+             name="color trans"
+             text_readonly_color="LabelDisabledColor"
+             top="6"
+             width="110">
+                Transparency %
+            </text>
+            <spinner
+             decimal_digits="0"
+             follows="left|top"
+             height="19"
+             increment="2"
+             initial_value="0"
+             layout="topleft"
+             left_delta="0"
+             max_val="100"
+             name="ColorTrans"
+             top_pad="4"
+             width="80" />
+            <text
+             type="string"
+             length="1"
+             follows="left|top"
+             height="10"
+             layout="topleft"
+             left_pad="15"
+             name="glow label"
+             text_readonly_color="LabelDisabledColor"
+             top="6"
+             width="80">
+                Glow
+            </text>
+            <spinner
+             decimal_digits="2"
+             follows="left|top"
+             height="19"
+             initial_value="0"
+             layout="topleft"
+             left_delta="0"
+             name="glow"
+             top_pad="4"
+             width="80" />
+            <check_box
+             height="19"
+             label="Full Bright"
+             layout="topleft"
+             left="7"
+             name="checkbox fullbright"
+             top_pad="4"
+             width="81" />
+            <combo_box
+             height="23"
+             layout="topleft"
+             left="10"
+             name="combobox matmedia"
+             top_pad="5"
+             width="100">
+                <combo_box.item
+                 label="Materials"
+                 name="Materials"
+                 value="Materials" />
+                <combo_box.item
+                 label="Media"
+                 name="Media"
+                 value="Media" />
+            </combo_box>
+            <combo_box
+             height="23"
+             layout="topleft"
+             left_pad="10"
+             name="combobox mattype"
+             top_delta="0"
+             width="155">
+                <combo_box.item
+                 label="Texture (diffuse)"
+                 name="Texture (diffuse)"
+                 value="Texture (diffuse)" />
+                <combo_box.item
+                 label="Bumpiness (normal)"
+                 name="Bumpiness (normal)"
+                 value="Bumpiness (normal)" />
+                <combo_box.item
+                 label="Shininess (specular)"
+                 name="Shininess (specular)"
+                 value="Shininess (specular)" />
+            </combo_box>
+            <texture_picker
+             can_apply_immediately="true"
+             default_image_name="Default"
+             fallback_image="materials_ui_x_24.png"
+             follows="left|top"
+             height="80"
+             label="Texture       "
+             layout="topleft"
+             left="10"
+             name="texture control"
+             tool_tip="Click to choose a picture"
+             top_pad="8"
+             width="64" />
+            <text
+             type="string"
+             length="1"
+             follows="left|top"
+             height="10"
+             layout="topleft"
+             left_pad="10"
+             name="label alphamode"
+             text_readonly_color="LabelDisabledColor"
+             top_delta="0"
+             width="90">
+                Alpha mode
+            </text>
+            <combo_box
+             height="23"
+             layout="topleft"
+             left_delta="0"
+             name="combobox alphamode"
+             top_pad="4"
+             width="120">
+                <combo_box.item
+                 label="None"
+                 name="None"
+                 value="None" />
+                <combo_box.item
+                 label="Alpha blending"
+                 name="Alpha blending"
+                 value="Alpha blending" />
+                <combo_box.item
+                 label="Alpha masking"
+                 name="Alpha masking"
+                 value="Alpha masking" />
+                <combo_box.item
+                 label="Emissive mask"
+                 name="Emissive mask"
+                 value="Emissive mask" />
+            </combo_box>
+            <text
+             type="string"
+             length="1"
+             follows="left|top"
+             height="10"
+             layout="topleft"
+             left_delta="0"
+             name="label maskcutoff"
+             text_readonly_color="LabelDisabledColor"
+             top_pad="4"
+             width="90">
+                Mask cutoff
+            </text>
+            <spinner
+             decimal_digits="0"
+             min_val="0"
+             max_val="255"
+             follows="left|top"
+             height="19"
+             initial_value="55"
+             layout="topleft"
+             top_pad="4"
+             left_delta="0"
+             increment="1"
+             name="maskcutoff"
+             width="80" />
+            <texture_picker
+             allow_no_texture="true"
+             can_apply_immediately="true"
+             default_image_name="Default"
+             fallback_image="materials_ui_x_24.png"
+             follows="left|top"
+             height="80"
+             label="Texture       "
+             layout="topleft"
+             left="10"
+             name="bumpytexture control"
+             tool_tip="Click to choose a picture"
+             top_delta="-55"
+             width="64" />
+            <text
+             type="string"
+             length="1"
+             follows="left|top"
+             height="10"
+             layout="topleft"
+             left_pad="10"
+             name="label bumpiness"
+             text_readonly_color="LabelDisabledColor"
+             top_delta="0"
+             width="90">
+                Bumpiness
+            </text>
+            <combo_box
+             height="23"
+             layout="topleft"
+             left_delta="0"
+             name="combobox bumpiness"
+             top_pad="4"
+             width="90">
+                <combo_box.item
+                 label="None"
+                 name="None"
+                 value="None" />
+                <combo_box.item
+                 label="Brightness"
+                 name="Brightness"
+                 value="Brightness" />
+                <combo_box.item
+                 label="Darkness"
+                 name="Darkness"
+                 value="Darkness" />
+                <combo_box.item
+                 label="woodgrain"
+                 name="woodgrain"
+                 value="woodgrain" />
+                <combo_box.item
+                 label="bark"
+                 name="bark"
+                 value="bark" />
+                <combo_box.item
+                 label="bricks"
+                 name="bricks"
+                 value="bricks" />
+                <combo_box.item
+                 label="checker"
+                 name="checker"
+                 value="checker" />
+                <combo_box.item
+                 label="concrete"
+                 name="concrete"
+                 value="concrete" />
+                <combo_box.item
+                 label="crustytile"
+                 name="crustytile"
+                 value="crustytile" />
+                <combo_box.item
+                 label="cutstone"
+                 name="cutstone"
+                 value="cutstone" />
+                <combo_box.item
+                 label="discs"
+                 name="discs"
+                 value="discs" />
+                <combo_box.item
+                 label="gravel"
+                 name="gravel"
+                 value="gravel" />
+                <combo_box.item
+                 label="petridish"
+                 name="petridish"
+                 value="petridish" />
+                <combo_box.item
+                 label="siding"
+                 name="siding"
+                 value="siding" />
+                <combo_box.item
+                 label="stonetile"
+                 name="stonetile"
+                 value="stonetile" />
+                <combo_box.item
+                 label="stucco"
+                 name="stucco"
+                 value="stucco" />
+                <combo_box.item
+                 label="suction"
+                 name="suction"
+                 value="suction" />
+                <combo_box.item
+                 label="weave"
+                 name="weave"
+                 value="weave" />
+              <!--
+                 NORSPEC-182, ensure item doesn't show up in menu until it should
+                <combo_box.item
+                 label="Use texture"
+                 name="Use texture"
+                 value="Use texture" />
+                 -->
+            </combo_box>
+            <texture_picker
+             allow_no_texture="true"
+             can_apply_immediately="true"
+             default_image_name="Default"
+             fallback_image="materials_ui_x_24.png"
+             follows="left|top"
+             height="80"
+             label="Texture       "
+             layout="topleft"
+             left="10"
+             name="shinytexture control"
+             tool_tip="Click to choose a picture"
+             top_delta="-14"
+             width="64" />
+            <text
+             type="string"
+             length="1"
+             follows="left|top"
+             height="10"
+             layout="topleft"
+             name="label shininess"
+             left_pad="10"
+             text_readonly_color="LabelDisabledColor"
+             top_delta="6"
+             width="90">
+                Shininess
+            </text>
+            <combo_box
+             height="23"
+             layout="topleft"
+             left_pad="10"
+             name="combobox shininess"
+             top_delta="-6"
+             width="90">
+                <combo_box.item
+                 label="None"
+                 name="None"
+                 value="None" />
+                <combo_box.item
+                 label="Low"
+                 name="Low"
+                 value="Low" />
+                <combo_box.item
+                 label="Medium"
+                 name="Medium"
+                 value="Medium" />
+                <combo_box.item
+                 label="High"
+                 name="High"
+                 value="High" />
+              <!--
+                 NORSPEC-182, ensure item doesn't show up in menu until it should
+                <combo_box.item
+                 label="Use texture"
+                 name="Use texture"
+                 value="Use texture" />
+                 -->
+            </combo_box>
+            <text
+             type="string"
+             length="1"
+             follows="left|top"
+             height="10"
+             layout="topleft"
+             left_delta="-100"
+             name="label glossiness"
+             text_readonly_color="LabelDisabledColor"
+             top_pad="8"
+             width="116">
+                Glossiness
+            </text>
+            <spinner
+             decimal_digits="0"
+             min_val="0"
+             max_val="255"
+             follows="left|top"
+             height="19"
+             initial_value="51"
+             increment="1"
+             layout="topleft"
+             top_delta="-4"
+             left_pad="10"
+             name="glossiness"
+             width="64" />
+            <text
+             type="string"
+             length="1"
+             follows="left|top"
+             height="10"
+             layout="topleft"
+             left_delta="-126"
+             name="label environment"
+             text_readonly_color="LabelDisabledColor"
+             top_pad="8"
+             width="116">
+                Environment
+            </text>
+            <spinner
+             decimal_digits="0"
+             min_val="0"
+             max_val="255"
+             increment="1"
+             follows="left|top"
+             height="19"
+             initial_value="0"
+             layout="topleft"
+             top_delta="-4"
+             left_pad="10"
+             name="environment"
+             width="64" />
+            <text
+             type="string"
+             length="1"
+             follows="left|top"
+             height="10"
+             layout="topleft"
+             left_delta="-126"
+             name="label shinycolor"
+             text_readonly_color="LabelDisabledColor"
+             top_pad="8"
+             width="116">
+                Color
+            </text>
+            <!-- label is blank because control places it below the box -->
+            <color_swatch
+             can_apply_immediately="true"
+             follows="left|top"
+             height="45"
+             label=""
+             layout="topleft"
+             left_pad="10"
+             name="shinycolorswatch"
+             tool_tip="Click to open color picker"
+             top_delta="-4"
+             width="64" />
+            <text
+			 follows="left|top|right"
+			 height="9"
+			 layout="topleft"
+			 left="10"
+			 top_delta="-50"
+             use_ellipses="true"
+			 read_only="true"
+			 name="media_info"
+			 width="280">
+			 URL of chosen media, if any, goes here
+			 </text>
+			<button
+			 follows="top|left"
+			 height="18"
+			 layout="topleft"
+			 left="10"
+			 name="add_media"
+			 top_pad="4"
+			 tool_tip="Add Media"
+			 label="Choose..."
+			 width="85">
+				<button.commit_callback
+				function="BuildTool.AddMedia"/>
+			</button>
+			<button
+			 follows="top|left"
+			 height="18"
+			 layout="topleft"
+			 left_pad="5"
+			 name="delete_media"
+			 tool_tip="Delete this media texture"
+			 top_delta="0"
+			 label="Remove"
+			 width="85">
+				<button.commit_callback
+				function="BuildTool.DeleteMedia"/>
+			</button>
+            <button
+			 follows="left|top"
+			 height="18"
+			 label="Align"
+			 label_selected="Align Media"
+			 layout="topleft"
+			 left_pad="5"
+			 name="button align"
+			 top_delta="0"
+			 tool_tip="Align media texture (must load first)"
+			 width="85" />
+            <text
+             type="string"
+             length="1"
+             follows="left|top"
+             height="10"
+             layout="topleft"
+             left="10"
+             name="tex gen"
+             text_readonly_color="LabelDisabledColor"
+             top_pad="60"
+             width="140">
+                Mapping
+            </text>
+            <combo_box
+             height="23"
+             layout="topleft"
+             left_pad="0"
+             name="combobox texgen"
+             top_pad="-13"
+             width="125">
+                <combo_box.item
+                 label="Default"
+                 name="Default"
+                 value="Default" />
+                <combo_box.item
+                 label="Planar"
+                 name="Planar"
+                 value="Planar" />
+            </combo_box>
+            <spinner
+             follows="left|top"
+             height="19"
+             initial_value="0"
+             label="Horizontal scale"
+             label_width="205"
+             layout="topleft"
+             left="10"
+             min_val="-100"
+             max_val="100"
+             name="TexScaleU"
+             top_pad="5"
+             width="265" />
+            <spinner
+             follows="left|top"
+             height="19"
+             initial_value="0"
+             label="Vertical scale"
+             label_width="205"
+             layout="topleft"
+             left="10"
+             min_val="-100"
+             max_val="100"
+             name="TexScaleV"
+             width="265" />
+            <spinner
+             decimal_digits="1"
+             follows="left|top"
+             height="19"
+             initial_value=""
+			 label="Repeats per meter"
+             layout="topleft"
+			 label_width="205"
+             left="10"
+             max_val="100"
+             min_val="0.1"
+             name="rptctrl"
+             width="265" />
+           <spinner
+             decimal_digits="2"
+             follows="left|top"
+             height="19"
+             increment="1"
+             initial_value="0"
+			 label="Rotation degrees"
+             layout="topleft"
+			 label_width="205"
+             left="10"
+             max_val="9999"
+             min_val="-9999"
+             name="TexRot"
+             width="265" />
+
+            <spinner
+             follows="left|top"
+             height="19"
+             initial_value="0"
+             label="Horizontal offset"
+             label_width="205"
+             layout="topleft"
+             left="10"
+             min_val="-1"
+             name="TexOffsetU"
+             width="265" />
+            <spinner
+             follows="left|top"
+             height="19"
+             initial_value="0"
+             label="Vertical offset"
+             label_width="205"
+             layout="topleft"
+             left="10"
+             min_val="-1"
+             name="TexOffsetV"
+             width="265" />
+            <spinner
+             follows="left|top"
+             height="19"
+             initial_value="0"
+             label="Horizontal scale"
+             label_width="205"
+             layout="topleft"
+             left="10"
+             min_val="-100"
+             max_val="100"
+             name="bumpyScaleU"
+             top_delta="-115"
+             width="265" />
+            <spinner
+             follows="left|top"
+             height="19"
+             initial_value="0"
+             label="Vertical scale"
+             label_width="205"
+             layout="topleft"
+             left="10"
+             min_val="-100"
+             max_val="100"
+             name="bumpyScaleV"
+             width="265" />
+           <spinner
+             decimal_digits="2"
+             follows="left|top"
+             height="19"
+             top_pad="27"
+             increment="1"
+             initial_value="0"
+			 label="Rotation degrees"
+             layout="topleft"
+			 label_width="205"
+             left="10"
+             max_val="360"
+             min_val="0"
+             name="bumpyRot"
+             width="265" />
+
+            <spinner
+             follows="left|top"
+             height="19"
+             initial_value="0"
+             label="Horizontal offset"
+             label_width="205"
+             layout="topleft"
+             left="10"
+             min_val="-1"
+             name="bumpyOffsetU"
+             width="265" />
+            <spinner
+             follows="left|top"
+             height="19"
+             initial_value="0"
+             label="Vertical offset"
+             label_width="205"
+             layout="topleft"
+             left="10"
+             min_val="-1"
+             name="bumpyOffsetV"
+             width="265" />
+            <spinner
+             follows="left|top"
+             height="19"
+             initial_value="0"
+             label="Horizontal scale"
+             label_width="205"
+             layout="topleft"
+             left="10"
+             min_val="-100"
+             max_val="100"
+             name="shinyScaleU"
+             top_delta="-115"
+             width="265" />
+            <spinner
+             follows="left|top"
+             height="19"
+             initial_value="0"
+             label="Vertical scale"
+             label_width="205"
+             layout="topleft"
+             left="10"
+             min_val="-100"
+             max_val="100"
+             name="shinyScaleV"
+             width="265" />
+           <spinner
+             decimal_digits="2"
+             follows="left|top"
+             height="19"
+             top_pad="27"
+             increment="1"
+             initial_value="0"
+			 label="Rotation degrees"
+             layout="topleft"
+			 label_width="205"
+             left="10"
+             max_val="360"
+             min_val="0"
+             name="shinyRot"
+             width="265" />
+
+            <spinner
+             follows="left|top"
+             height="19"
+             initial_value="0"
+             label="Horizontal offset"
+             label_width="205"
+             layout="topleft"
+             left="10"
+             min_val="-1"
+             name="shinyOffsetU"
+             width="265" />
+            <spinner
+             follows="left|top"
+             height="19"
+             initial_value="0"
+             label="Vertical offset"
+             label_width="205"
+             layout="topleft"
+             left="10"
+             min_val="-1"
+             name="shinyOffsetV"
+             width="265" />
+            <check_box
+             follows="top|left"
+             height="16"
+             initial_value="false"
+             label="Align planar faces"
+             layout="topleft"
+             left="7"
+             name="checkbox planar align"
+             tool_tip="Align textures on all selected faces with the last selected face. Requires Planar texture mapping."
+             top_delta="16"
+             width="260" />
+            <web_browser
+             visible="false"
+             enabled="false"
+             border_visible="true"
+             bottom_delta="0"
+             follows="top|left"
+             left="0"
+             name="title_media"
+             width="4"
+             height="4"
+             start_url="about:blank"
+             decouple_texture_size="true" />
+	   </panel>
diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml
index 3b57ff5fd67e8da54edbdfa61b4b62c4a49aa2cb..f7b33b0a4ad39d1591952416a43260d839d75821 100755
--- a/indra/newview/skins/default/xui/en/strings.xml
+++ b/indra/newview/skins/default/xui/en/strings.xml
@@ -373,6 +373,8 @@ Please try logging in again in a minute.</string>
 	<!-- build floater -->
 	<string name="multiple_textures">Multiple</string>
 
+<string name="use_texture">Use texture</string>
+
 	<!-- world map -->
 	<string name="texture_loading">Loading...</string>
 	<string name="worldmap_offline">Offline</string>
@@ -416,7 +418,7 @@ Please try logging in again in a minute.</string>
 	<string name="OverrideYourAnimations">Replace your default animations</string>
 	<string name="ScriptReturnObjects">Return objects on your behalf</string>
 	<string name="UnknownScriptPermission">(unknown)!</string>
-	
+
 	<!-- Sim Access labels -->
 	<string name="SIM_ACCESS_PG">General</string>
 	<string name="SIM_ACCESS_MATURE">Moderate</string>
diff --git a/indra/newview/skins/default/xui/es/menu_viewer.xml b/indra/newview/skins/default/xui/es/menu_viewer.xml
index 30842f53f269b375ea9eceb208f26ea51416b757..1e0ceb2220522f4b525942315738d14d58200232 100755
--- a/indra/newview/skins/default/xui/es/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/es/menu_viewer.xml
@@ -293,7 +293,7 @@
 		<menu label="Rendering" name="Rendering">
 			<menu_item_check label="Axes" name="Axes"/>
 			<menu_item_check label="Wireframe" name="Wireframe"/>
-			<menu_item_check label="Luces y sombras" name="Lighting and Shadows"/>
+			<menu_item_check label="Luces y sombras" name="Advanced Lighting Model"/>
 			<menu_item_check label="Sombras del sol/la luna/proyectores" name="Shadows from Sun/Moon/Projectors"/>
 			<menu_item_check label="SSAO y sombras suavizadas" name="SSAO and Shadow Smoothing"/>
 			<menu_item_check label="Capas alfa automáticas (deferidas)" name="Automatic Alpha Masks (deferred)"/>
diff --git a/indra/newview/skins/default/xui/fr/menu_viewer.xml b/indra/newview/skins/default/xui/fr/menu_viewer.xml
index 457b756c7d518bd21939d9b1a0e5b6f6ad051713..548f144742e6026a0cacd38dc2cb80ea839cdcfe 100755
--- a/indra/newview/skins/default/xui/fr/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/fr/menu_viewer.xml
@@ -315,7 +315,7 @@
 			<menu_item_call label="Base des infos de la texture sélectionnée" name="Selected Texture Info Basis"/>
 			<menu_item_check label="Filaire" name="Wireframe"/>
 			<menu_item_check label="Occlusion objet-objet" name="Object-Object Occlusion"/>
-			<menu_item_check label="Éclairage et ombres" name="Lighting and Shadows"/>
+			<menu_item_check label="Éclairage et ombres" name="Advanced Lighting Model"/>
 			<menu_item_check label="Ombres du soleil/de la lune/des projecteurs" name="Shadows from Sun/Moon/Projectors"/>
 			<menu_item_check label="SSAO et lissage des ombres" name="SSAO and Shadow Smoothing"/>
 			<menu_item_check label="Débogage GL" name="Debug GL"/>
diff --git a/indra/newview/skins/default/xui/it/menu_viewer.xml b/indra/newview/skins/default/xui/it/menu_viewer.xml
index c93b92029f6d6d796111560c4c8bba755e3a999a..2b7bc71df799080eb96c48bc60034595e5d92267 100755
--- a/indra/newview/skins/default/xui/it/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/it/menu_viewer.xml
@@ -294,7 +294,7 @@
 		<menu label="Rendering" name="Rendering">
 			<menu_item_check label="Assi" name="Axes"/>
 			<menu_item_check label="Wireframe" name="Wireframe"/>
-			<menu_item_check label="Luci e ombre" name="Lighting and Shadows"/>
+			<menu_item_check label="Luci e ombre" name="Advanced Lighting Model"/>
 			<menu_item_check label="Ombra dal sole, dalla luna e dai proiettori" name="Shadows from Sun/Moon/Projectors"/>
 			<menu_item_check label="SSAO e ombre fluide" name="SSAO and Shadow Smoothing"/>
 			<menu_item_check label="Maschera alfa automatica (differita)" name="Automatic Alpha Masks (deferred)"/>
diff --git a/indra/newview/skins/default/xui/ja/menu_viewer.xml b/indra/newview/skins/default/xui/ja/menu_viewer.xml
index 6f650242b4e91e6fda546450ad988f02f76e666b..89f58d3bacecf0fce59859f02b408589b81ac2b0 100755
--- a/indra/newview/skins/default/xui/ja/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/ja/menu_viewer.xml
@@ -315,7 +315,7 @@
 			<menu_item_call label="選択したテクスチャ情報基底" name="Selected Texture Info Basis"/>
 			<menu_item_check label="ワイヤーフレーム" name="Wireframe"/>
 			<menu_item_check label="オブジェクト間オクルージョン" name="Object-Object Occlusion"/>
-			<menu_item_check label="光と影" name="Lighting and Shadows"/>
+			<menu_item_check label="光と影" name="Advanced Lighting Model"/>
 			<menu_item_check label="太陽・月・プロジェクタからの影" name="Shadows from Sun/Moon/Projectors"/>
 			<menu_item_check label="SSAO と影の平滑化" name="SSAO and Shadow Smoothing"/>
 			<menu_item_check label="GL デバッグ" name="Debug GL"/>
diff --git a/indra/newview/skins/default/xui/pl/menu_viewer.xml b/indra/newview/skins/default/xui/pl/menu_viewer.xml
index 24c961fa2659b0096c9563329c12831a0d7d9f62..e1725fc30865db1f805db6ed7906fd707891c37a 100755
--- a/indra/newview/skins/default/xui/pl/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/pl/menu_viewer.xml
@@ -236,7 +236,7 @@
 		<menu label="Renderowanie" name="Rendering">
 			<menu_item_check label="Osie" name="Axes"/>
 			<menu_item_check label="Tryb obrazu szkieletowego" name="Wireframe"/>
-			<menu_item_check label="Oświetlenie i cienie" name="Lighting and Shadows"/>
+			<menu_item_check label="Oświetlenie i cienie" name="Advanced Lighting Model"/>
 			<menu_item_check label="Cienie Słońca/Księżyca/Projektory" name="Shadows from Sun/Moon/Projectors"/>
 			<menu_item_check label="SSAO and wygładzanie cienia" name="SSAO and Shadow Smoothing"/>
 			<menu_item_check label="Globalne oświetlenie (eksperymentalne)" name="Global Illumination"/>
diff --git a/indra/newview/skins/default/xui/pt/menu_viewer.xml b/indra/newview/skins/default/xui/pt/menu_viewer.xml
index 703df84efb51526697b7fc414c2ecd20c2987536..15814fed4cfe8015c5ef1f03f28bb22d76d1c3a8 100755
--- a/indra/newview/skins/default/xui/pt/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/pt/menu_viewer.xml
@@ -294,7 +294,7 @@
 		<menu label="Rendering" name="Rendering">
 			<menu_item_check label="Axes" name="Axes"/>
 			<menu_item_check label="Wireframe" name="Wireframe"/>
-			<menu_item_check label="Iluminação e sombras" name="Lighting and Shadows"/>
+			<menu_item_check label="Iluminação e sombras" name="Advanced Lighting Model"/>
 			<menu_item_check label="Sombras da projeção do sol/lua" name="Shadows from Sun/Moon/Projectors"/>
 			<menu_item_check label="SSAO e sombra suave" name="SSAO and Shadow Smoothing"/>
 			<menu_item_check label="Máscaras alpha automáticas (adiadas)" name="Automatic Alpha Masks (deferred)"/>
diff --git a/indra/newview/skins/default/xui/ru/menu_viewer.xml b/indra/newview/skins/default/xui/ru/menu_viewer.xml
index d6625361c58789bd5ec0e3aa71ff84456680171f..92a9943b937f13bce73bde7990506e5874f4b701 100755
--- a/indra/newview/skins/default/xui/ru/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/ru/menu_viewer.xml
@@ -114,6 +114,7 @@
 			<menu_item_call label="Купить" name="Menu Object Buy"/>
 			<menu_item_call label="Взять" name="Menu Object Take"/>
 			<menu_item_call label="Взять копию" name="Take Copy"/>
+			<menu_item_call label="Сохранить в моем инвентаре" name="Save Object Back to My Inventory"/>
 			<menu_item_call label="Сохранить в контенте объектов" name="Save Object Back to Object Contents"/>
 			<menu_item_call label="Вернуть объект" name="Return Object back to Owner"/>
 		</menu>
@@ -128,7 +129,6 @@
 			<menu_item_call label="Наборы связей..." name="pathfinding_linksets_menu_item"/>
 			<menu_item_call label="Персонажи..." name="pathfinding_characters_menu_item"/>
 			<menu_item_call label="Просмотр/тестирование..." name="pathfinding_console_menu_item"/>
-			<menu_item_call label="Восстановить регион" name="pathfinding_rebake_navmesh_item"/>
 		</menu>
 		<menu label="Параметры" name="Options">
 			<menu_item_check label="Показать расширенные разрешения" name="DebugPermissions"/>
@@ -158,13 +158,6 @@
 	<menu label="Справка" name="Help">
 		<menu_item_call label="Инструкции..." name="How To"/>
 		<menu_item_call label="Справка по [SECOND_LIFE]" name="Second Life Help"/>
-		<menu_item_call label="Руководство пользователя" name="User’s guide"/>
-		<menu_item_call label="База знаний" name="Knowledge Base"/>
-		<menu_item_call label="Wiki" name="Wiki"/>
-		<menu_item_call label="Форумы сообщества" name="Community Forums"/>
-		<menu_item_call label="Портал поддержки" name="Support portal"/>
-		<menu_item_call label="Новости [SECOND_LIFE]" name="Second Life News"/>
-		<menu_item_call label="Блоги [SECOND_LIFE]" name="Second Life Blogs"/>
 		<menu_item_call label="Жалоба" name="Report Abuse"/>
 		<menu_item_call label="Сообщить об ошибке" name="Report Bug"/>
 		<menu_item_call label="О [APP_NAME]" name="About Second Life"/>
@@ -313,7 +306,7 @@
 			<menu_item_call label="Выбранная текстура в основе" name="Selected Texture Info Basis"/>
 			<menu_item_check label="Каркас" name="Wireframe"/>
 			<menu_item_check label="Смыкание объектов" name="Object-Object Occlusion"/>
-			<menu_item_check label="Освещение и тени" name="Lighting and Shadows"/>
+			<menu_item_check label="Освещение и тени" name="Advanced Lighting Model"/>
 			<menu_item_check label="Тени от солнца, луны и прожекторов" name="Shadows from Sun/Moon/Projectors"/>
 			<menu_item_check label="SSAO и сглаживание теней" name="SSAO and Shadow Smoothing"/>
 			<menu_item_check label="Отладка GL" name="Debug GL"/>
@@ -391,14 +384,9 @@
 				<menu_item_call label="Проверка женщины" name="Test Female"/>
 				<menu_item_check label="Разрешить выбор аватара" name="Allow Select Avatar"/>
 			</menu>
-			<menu label="Скорость анимации" name="Animation Speed">
-				<menu_item_call label="Ускорить все анимации на 10%" name="All Animations 10 Faster"/>
-				<menu_item_call label="Замедлить все анимации на 10%" name="All Animations 10 Slower"/>
-				<menu_item_call label="Восстановить скорость анимаций" name="Reset All Animation Speed"/>
-				<menu_item_check label="Анимация медленных движений" name="Slow Motion Animations"/>
-			</menu>
 			<menu_item_call label="Скинуть параметры" name="Force Params to Default"/>
 			<menu_item_check label="Данные об анимации" name="Animation Info"/>
+			<menu_item_check label="Анимация медленных движений" name="Slow Motion Animations"/>
 			<menu_item_check label="Показать взгляд" name="Show Look At"/>
 			<menu_item_check label="Показать указание" name="Show Point At"/>
 			<menu_item_check label="Отладка обновленных движений суставов" name="Debug Joint Updates"/>
diff --git a/indra/newview/skins/default/xui/tr/menu_viewer.xml b/indra/newview/skins/default/xui/tr/menu_viewer.xml
index c465966fc7ee11da475a8fcdd5f5e280eb6fdec9..35485bb292b303cfa307bfceac4888f620587016 100755
--- a/indra/newview/skins/default/xui/tr/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/tr/menu_viewer.xml
@@ -313,7 +313,7 @@
 			<menu_item_call label="Seçilen Doku Bilgi Temeli" name="Selected Texture Info Basis"/>
 			<menu_item_check label="Telkafes" name="Wireframe"/>
 			<menu_item_check label="Görünen Nesneler İçin Gölgeleme" name="Object-Object Occlusion"/>
-			<menu_item_check label="Işıklandırma ve Gölgeler" name="Lighting and Shadows"/>
+			<menu_item_check label="Işıklandırma ve Gölgeler" name="Advanced Lighting Model"/>
 			<menu_item_check label="Güneş/Ay/Projektörlerden Gelen Gölgeler" name="Shadows from Sun/Moon/Projectors"/>
 			<menu_item_check label="SSAO ve Gölge Yumuşatma" name="SSAO and Shadow Smoothing"/>
 			<menu_item_check label="GL Hata Ayıklama" name="Debug GL"/>
diff --git a/indra/newview/skins/default/xui/zh/menu_viewer.xml b/indra/newview/skins/default/xui/zh/menu_viewer.xml
index 09bdc578196748945cc820c5593b0f8d3193286f..d4844b191b5f5e19c2e53d1775a2c680b40731b5 100755
--- a/indra/newview/skins/default/xui/zh/menu_viewer.xml
+++ b/indra/newview/skins/default/xui/zh/menu_viewer.xml
@@ -313,7 +313,7 @@
 			<menu_item_call label="已選取材質資訊基礎" name="Selected Texture Info Basis"/>
 			<menu_item_check label="線框" name="Wireframe"/>
 			<menu_item_check label="物件導向的遮蔽" name="Object-Object Occlusion"/>
-			<menu_item_check label="光線和陰影" name="Lighting and Shadows"/>
+			<menu_item_check label="光線和陰影" name="Advanced Lighting Model"/>
 			<menu_item_check label="來自日/月/投影物的陰影" name="Shadows from Sun/Moon/Projectors"/>
 			<menu_item_check label="屏幕空間環境光遮蔽和陰影平滑技術" name="SSAO and Shadow Smoothing"/>
 			<menu_item_check label="GL 除錯" name="Debug GL"/>
diff --git a/indra/newview/tests/llmediadataclient_test.cpp b/indra/newview/tests/llmediadataclient_test.cpp
index 41cb344808371cf9dc9c87fe31c28b7f09a9782d..3e55336f2de25e454488a1e37b190210bb273de3 100755
--- a/indra/newview/tests/llmediadataclient_test.cpp
+++ b/indra/newview/tests/llmediadataclient_test.cpp
@@ -39,6 +39,7 @@
 #include "../llvovolume.h"
 
 #include "../../llprimitive/llmediaentry.cpp"
+#include "../../llprimitive/llmaterialid.cpp"
 #include "../../llprimitive/lltextureentry.cpp"
 #include "../../llmessage/tests/llcurl_stub.cpp"
 
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 2578c81224ad648f3b7b247a78f0f9a25f75df72..53a3e732caa52401624638432d38645154d6c9d2 100755
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -172,7 +172,7 @@ def channel_lowerword(self):
     def app_name(self):
         app_suffix='Test'
         channel_type=self.channel_lowerword()
-        if channel_type == 'release' :
+        if channel_type.startswith('release') :
             app_suffix='Viewer'
         elif re.match('^(beta|project).*',channel_type) :
             app_suffix=self.channel_unique()
@@ -182,8 +182,8 @@ def icon_path(self):
         icon_path="icons/"
         channel_type=self.channel_lowerword()
         print "Icon channel type '%s'" % channel_type
-        if channel_type == 'release' :
-            icon_path += channel_type
+        if channel_type.startswith('release') :
+            icon_path += 'release'
         elif re.match('^beta.*',channel_type) :
             icon_path += 'beta'
         elif re.match('^project.*',channel_type) :
@@ -242,7 +242,7 @@ class WindowsManifest(ViewerManifest):
     def final_exe(self):
         app_suffix="Test"
         channel_type=self.channel_lowerword()
-        if channel_type == 'release' :
+        if channel_type.startswith('release') :
             app_suffix=''
         elif re.match('^(beta|project).*',channel_type) :
             app_suffix=''.join(self.channel_unique().split())
@@ -729,7 +729,7 @@ def path_optional(src, dst):
                                 'SLVoice',
                                 ):
                      self.path2basename(libdir, libfile)
-
+                
                 # our apps
                 for app_bld_dir, app in (("mac_crash_logger", "mac-crash-logger.app"),
                                          # plugin launcher
@@ -1038,9 +1038,6 @@ def construct(self):
             self.path("libboost_signals-mt.so.*")
             self.path("libboost_system-mt.so.*")
             self.path("libboost_thread-mt.so.*")
-            self.path("libbreakpad_client.so.0.0.0")
-            self.path("libbreakpad_client.so.0")
-            self.path("libbreakpad_client.so")
             self.path("libcollada14dom.so")
             self.path("libdb*.so")
             self.path("libcrypto.so.*")
diff --git a/indra/test/llsaleinfo_tut.cpp b/indra/test/llsaleinfo_tut.cpp
index 2689eaa15e5f0088e72e9918ae5adf75a78a25ae..2488af1d7f0dee00843954d62b2e143cb1e43a82 100755
--- a/indra/test/llsaleinfo_tut.cpp
+++ b/indra/test/llsaleinfo_tut.cpp
@@ -156,7 +156,7 @@ namespace tut
 					
 		ensure("importStream() fn failed ",
 			llsaleinfo.getSalePrice() == llsaleinfo1.getSalePrice() &&
-			llsaleinfo.getSaleType() == llsaleinfo1.getSaleType());
+										       llsaleinfo.getSaleType() == llsaleinfo1.getSaleType());		
 	}
 
 	template<> template<>
diff --git a/indra/viewer_components/login/lllogin.cpp b/indra/viewer_components/login/lllogin.cpp
index 3357ad812d8c771babc2633681884c4d62e8939a..8f33b2ad58f96b675a667e71dad06df6c5b38fb1 100755
--- a/indra/viewer_components/login/lllogin.cpp
+++ b/indra/viewer_components/login/lllogin.cpp
@@ -137,7 +137,7 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_para
 	//{
 	//	printable_params["params"]["passwd"] = "*******";
 	//}
-    LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::instance().getName(self)
+	LL_DEBUGS("LLLogin") << "Entering coroutine " << LLCoros::instance().getName(self)
                         << " with uri '" << uri << "', parameters " << printable_params << LL_ENDL;
 
 	// Arriving in SRVRequest state
@@ -146,23 +146,23 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_para
 
     LLSD rewrittenURIs;
     {
-        LLEventTimeout filter(replyPump);
-        sendProgressEvent("offline", "srvrequest");
+		LLEventTimeout filter(replyPump);
+		sendProgressEvent("offline", "srvrequest");
 
-        // Request SRV record.
-        LL_DEBUGS("LLLogin") << "Requesting SRV record from " << uri << LL_ENDL;
+      // Request SRV record.
+		LL_DEBUGS("LLLogin") << "Requesting SRV record from " << uri << LL_ENDL;
 
-        // *NOTE:Mani - Completely arbitrary default timeout value for SRV request.
+      // *NOTE:Mani - Completely arbitrary default timeout value for SRV request.
 		F32 seconds_to_timeout = 5.0f;
 		if(login_params.has("cfg_srv_timeout"))
 		{
 			seconds_to_timeout = login_params["cfg_srv_timeout"].asReal();
 		}
 
-        // If the SRV request times out (e.g. EXT-3934), simulate response: an
-        // array containing our original URI.
-        LLSD fakeResponse(LLSD::emptyArray());
-        fakeResponse.append(uri);
+		// If the SRV request times out (e.g. EXT-3934), simulate response: an
+		// array containing our original URI.
+		LLSD fakeResponse(LLSD::emptyArray());
+		fakeResponse.append(uri);
 		filter.eventAfter(seconds_to_timeout, fakeResponse);
 
 		std::string srv_pump_name = "LLAres";
@@ -172,13 +172,13 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_para
 		}
 
 		// Make request
-        LLSD request;
-        request["op"] = "rewriteURI";
-        request["uri"] = uri;
-        request["reply"] = replyPump.getName();
-        rewrittenURIs = postAndWait(self, request, srv_pump_name, filter);
-        // EXP-772: If rewrittenURIs fail, try original URI as a fallback.
-        rewrittenURIs.append(uri);
+		LLSD request;
+		request["op"] = "rewriteURI";
+		request["uri"] = uri;
+		request["reply"] = replyPump.getName();
+		rewrittenURIs = postAndWait(self, request, srv_pump_name, filter);
+		// EXP-772: If rewrittenURIs fail, try original URI as a fallback.
+		rewrittenURIs.append(uri);
     } // we no longer need the filter
 
     LLEventPump& xmlrpcPump(LLEventPumps::instance().obtain("LLXMLRPCTransaction"));
@@ -230,7 +230,7 @@ void LLLogin::Impl::login_(LLCoros::self& self, std::string uri, LLSD login_para
                 // Still Downloading -- send progress update.
                 sendProgressEvent("offline", "downloading");
             }
-				 
+	
 			LL_DEBUGS("LLLogin") << "Auth Response: " << mAuthResponse << LL_ENDL;
             status = mAuthResponse["status"].asString();